1- import { ENTER } from '@codesandbox/common/lib/utils/keycodes' ;
1+ import { ENTER , ESC } from '@codesandbox/common/lib/utils/keycodes' ;
22import { hasPermission } from '@codesandbox/common/lib/utils/permission' ;
3+
34import {
45 Avatar ,
56 Element ,
@@ -33,7 +34,7 @@ export const CommentDialog = props =>
3334 ReactDOM . createPortal ( < Dialog { ...props } /> , document . body ) ;
3435
3536export const Dialog : React . FC = ( ) => {
36- const { state } = useOvermind ( ) ;
37+ const { state, actions } = useOvermind ( ) ;
3738 const controller = useAnimation ( ) ;
3839
3940 const comment = state . comments . currentComment ;
@@ -96,6 +97,17 @@ export const Dialog: React.FC = () => {
9697 setDragging ( false ) ;
9798 } ;
9899
100+ React . useEffect ( ( ) => {
101+ const listener = event => {
102+ if ( event . which === ESC ) {
103+ actions . comments . closeComment ( ) ;
104+ }
105+ } ;
106+
107+ document . addEventListener ( 'keydown' , listener ) ;
108+ return ( ) => document . removeEventListener ( 'keydown' , listener ) ;
109+ } , [ actions . comments ] ) ;
110+
99111 if ( ! currentCommentPositions ) {
100112 return null ;
101113 }
@@ -152,9 +164,11 @@ export const Dialog: React.FC = () => {
152164 />
153165
154166 < Replies
167+ key = { comment . id }
155168 replies = { replies }
156169 replyCount = { comment . replyCount }
157170 repliesRenderedCallback = { ( ) => setRepliesRendered ( true ) }
171+ listRef = { listRef }
158172 />
159173 </ Element >
160174 < AddReply
@@ -279,6 +293,7 @@ const DialogHeader = ({ comment, hasShadow }) => {
279293 } = useOvermind ( ) ;
280294
281295 const closeDialog = ( ) => comments . closeComment ( ) ;
296+
282297 const canResolve =
283298 hasPermission ( editor . currentSandbox . authorization , 'write_project' ) ||
284299 comment . user . id === user . id ;
@@ -412,7 +427,7 @@ const CommentBody = ({ comment, editing, setEditing, hasReplies }) => {
412427 ) ;
413428} ;
414429
415- const Replies = ( { replies, replyCount, repliesRenderedCallback } ) => {
430+ const Replies = ( { replies, replyCount, listRef , repliesRenderedCallback } ) => {
416431 /**
417432 * Loading animations:
418433 * 0. Wait for the dialog to have animated in view and scaled up.
@@ -424,20 +439,23 @@ const Replies = ({ replies, replyCount, repliesRenderedCallback }) => {
424439 *
425440 */
426441
427- const skeletonController = useAnimation ( ) ;
428- const repliesController = useAnimation ( ) ;
429-
430- /** Wait another <delay>ms after the dialog has transitioned into view */
431- const delay = DIALOG_TRANSITION_DURATION + REPLY_TRANSITION_DELAY ;
432- const REPLY_TRANSITION_DURATION = Math . max ( replyCount * 0.15 , 0.5 ) ;
433- const SKELETON_FADE_DURATION = 0.25 ;
434- const SKELETON_HEIGHT = 146 ;
435- const repliesLoaded = replies . length === replyCount ;
436442 // initial status of replies -
437443 // this is false when it's the first time this specific comment is opened
438444 // after that it will be true because we cache replies in state
445+ const repliesLoaded = replies . length === replyCount ;
439446 const repliesAlreadyLoadedOnFirstRender = React . useRef ( repliesLoaded ) ;
440447
448+ /** CONSTANTS:
449+ * Wait another <delay> after the dialog has transitioned into view
450+ * These are in s not ms
451+ */
452+ const delay = DIALOG_TRANSITION_DURATION + REPLY_TRANSITION_DELAY ;
453+ const SKELETON_FADE_DURATION = 0.25 ;
454+ const SKELETON_HEIGHT = 146 ;
455+ const REPLY_TRANSITION_DURATION = repliesLoaded
456+ ? 0
457+ : Math . max ( replyCount * 0.15 , 0.5 ) ;
458+
441459 // current status of replies-
442460 /** Welcome to the imperative world of timeline animations
443461 *
@@ -455,6 +473,8 @@ const Replies = ({ replies, replyCount, repliesRenderedCallback }) => {
455473 */
456474
457475 const [ T , setStepInTimeline ] = React . useState ( - 1 ) ;
476+ const skeletonController = useAnimation ( ) ;
477+ const repliesController = useAnimation ( ) ;
458478
459479 /*
460480 * T = 0 (DOM has rendered, animations can be started)
@@ -541,6 +561,22 @@ const Replies = ({ replies, replyCount, repliesRenderedCallback }) => {
541561 repliesController ,
542562 ] ) ;
543563
564+ React . useEffect ( ( ) => {
565+ // when the animations are done, scroll to last reply
566+ let timeout ;
567+
568+ if ( T === 2 ) {
569+ timeout = window . setTimeout ( ( ) => {
570+ listRef . current . scrollTo ( {
571+ top : listRef . current . scrollHeight ,
572+ behavior : 'smooth' ,
573+ } ) ;
574+ } , REPLY_TRANSITION_DURATION * 1000 ) ;
575+ }
576+
577+ return ( ) => window . clearTimeout ( timeout ) ;
578+ } , [ T , listRef , REPLY_TRANSITION_DURATION ] ) ;
579+
544580 return (
545581 < >
546582 < motion . div
0 commit comments