diff --git a/editor/src/components/canvas/controls/comment-popup.tsx b/editor/src/components/canvas/controls/comment-popup.tsx index 237a8deaf026..b16e19a6ee74 100644 --- a/editor/src/components/canvas/controls/comment-popup.tsx +++ b/editor/src/components/canvas/controls/comment-popup.tsx @@ -143,6 +143,27 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => { } }, []) + const getLiveblocksEditorElement = React.useCallback(() => { + if (composerRef.current == null) { + return null + } + + const composerTextbox = getComposerTextbox() + if (composerTextbox == null) { + return null + } + + scrollToBottom() + + return composerTextbox + }, [scrollToBottom]) + + const triggerAutoFocus = React.useCallback(() => { + setTimeout(() => { + getLiveblocksEditorElement()?.focus() + }, 0) + }, [getLiveblocksEditorElement]) + const onCreateThread = React.useCallback( ({ body }: ComposerSubmitComment, event: React.FormEvent) => { event.preventDefault() @@ -207,32 +228,25 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => { switchEditorMode(EditorModes.commentMode(existingComment(newThread.id), 'not-dragging')), setRightMenuTab(RightMenuTab.Comments), ]) + triggerAutoFocus() }, - [createThread, comment, dispatch, remixSceneRoutes, scenes, createNewThreadReadStatus], + [ + comment, + createNewThreadReadStatus, + dispatch, + triggerAutoFocus, + createThread, + scenes, + remixSceneRoutes, + ], ) const onSubmitComment = React.useCallback(() => { if (threadId != null) { createNewThreadReadStatus(threadId, 'read') } - function getLiveblocksEditorElement(): HTMLDivElement | null { - if (composerRef.current == null) { - return null - } - - const composerTextbox = getComposerTextbox() - if (composerTextbox == null) { - return null - } - - scrollToBottom() - - return composerTextbox - } - setTimeout(() => { - getLiveblocksEditorElement()?.focus() - }, 0) - }, [threadId, createNewThreadReadStatus, scrollToBottom]) + triggerAutoFocus() + }, [threadId, triggerAutoFocus, createNewThreadReadStatus]) const onCommentDelete = React.useCallback( (_deleted: CommentData) => { @@ -278,8 +292,6 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => { setThreadReadStatus(thread.id, 'unread') }, [thread?.id, setThreadReadStatus]) - const collabs = useStorage((storage) => storage.collaborators) - const onScroll = () => { const element = listRef.current if (element == null) { @@ -332,73 +344,83 @@ const CommentThread = React.memo(({ comment }: CommentThreadProps) => { onKeyUp={stopPropagation} onMouseUp={stopPropagation} > - {thread == null ? ( - - ) : ( - <> - + + {when( + readByMe === 'read', + + + , + )} + + + + + +
+
- {when( - readByMe === 'read', - - - , - )} - - - - - -
-
- {thread.comments.map((c) => { - return ( - - ) - })} -
- - + ) + })} +
+ + + {thread == null ? null : ( 0 && showShadowTop} comment={thread.comments[0]} /> -
+ )} +
+ {thread == null ? ( + ) : ( + { style={ComposerStyle} onKeyDown={onExistingCommentComposerKeyDown} /> - - )} + )} + ) }) CommentThread.displayName = 'CommentThread' -type NewCommentPopupProps = { - onComposerSubmit: ( - comment: ComposerSubmitComment, - event: React.FormEvent, - ) => void -} - -const NewCommentPopup = React.memo((props: NewCommentPopupProps) => { - const dispatch = useDispatch() - - const onNewCommentComposerKeyDown = React.useCallback( - (e: React.KeyboardEvent) => switchToBasicCommentModeOnEscape(e, dispatch), - [dispatch], - ) - - const newCommentComposerAnimation = useAnimation() - - const onClickOutsideNewComment = React.useCallback( - (e: React.MouseEvent) => { - e.preventDefault() - e.stopPropagation() - - const composerTextbox = getComposerTextbox() - if (composerTextbox != null) { - function findPlaceholderChild(element: Element) { - if (element == null) { - return false - } - if (element.attributes.getNamedItem('data-placeholder') != null) { - return true - } - if (element.children.length < 1) { - return false - } - return findPlaceholderChild(element.children[0]) - } - - const isEmpty = composerTextbox.innerText.trim().length === 0 - const isPlaceholder = !isEmpty && findPlaceholderChild(composerTextbox.children[0]) - - // if the contents of the new comment are empty... - if (isEmpty || isPlaceholder) { - // ...just close the popup - dispatch([switchEditorMode(EditorModes.commentMode(null, 'not-dragging'))]) - } else { - // ...otherwise, shake the popup and re-focus its text box - const shakeDelta = 4 // px - void newCommentComposerAnimation.start({ - x: [-shakeDelta, shakeDelta, -shakeDelta, shakeDelta, 0], - borderColor: [ - colorTheme.error.cssValue, - colorTheme.error.cssValue, - colorTheme.error.cssValue, - colorTheme.error.cssValue, - '#00000000', // transparent, animatable - ], - transition: { duration: 0.2 }, - }) - } - - composerTextbox.focus() - } - }, - [newCommentComposerAnimation, dispatch], - ) - - const onClickClose = React.useCallback(() => { - dispatch([switchEditorMode(EditorModes.commentMode(null, 'not-dragging'))]) - }, [dispatch]) - - return ( - <> -
-
- -
- - - - - ) -}) -NewCommentPopup.displayName = 'NewCommentPopup' - const ListShadow = React.memo( ({ enabled, position }: { enabled: boolean; position: 'top' | 'bottom' }) => { return (