11"use client" ;
22
3- import { mergeCSSClasses } from "@blocknote/core" ;
3+ import { Dictionary , mergeCSSClasses } from "@blocknote/core" ;
44import { CommentsExtension } from "@blocknote/core/comments" ;
55import type { CommentData , ThreadData } from "@blocknote/core/comments" ;
6- import { MouseEvent , ReactNode , useCallback , useState } from "react" ;
6+ import { ThreadStore } from "@blocknote/core/comments" ;
7+ import { MouseEvent , ReactNode , memo , useCallback , useState } from "react" ;
78import {
89 RiArrowGoBackFill ,
910 RiCheckFill ,
@@ -13,7 +14,7 @@ import {
1314 RiMoreFill ,
1415} from "react-icons/ri" ;
1516
16- import { useComponentsContext } from "../../editor/ComponentsContext.js" ;
17+ import { Components , useComponentsContext } from "../../editor/ComponentsContext.js" ;
1718import { useCreateBlockNote } from "../../hooks/useCreateBlockNote.js" ;
1819import { useExtension } from "../../hooks/useExtension.js" ;
1920import { useDictionary } from "../../i18n/dictionary.js" ;
@@ -23,6 +24,103 @@ import { ReactionBadge } from "./ReactionBadge.js";
2324import { defaultCommentEditorSchema } from "./defaultCommentEditorSchema.js" ;
2425import { useUser } from "./useUsers.js" ;
2526
27+ type CommentEditorActionsProps = {
28+ isFocused : boolean ;
29+ isEmpty : boolean ;
30+ comment : CommentData ;
31+ isEditing : boolean ;
32+ threadStore : ThreadStore ;
33+ onReactionSelect : ( emoji : string ) => Promise < void > ;
34+ onEditSubmit : ( event : MouseEvent ) => Promise < void > ;
35+ onEditCancel : ( ) => void ;
36+ onEmojiPickerOpenChange : ( open : boolean ) => void ;
37+ Components : Components ;
38+ dict : Dictionary ;
39+ } ;
40+
41+ const CommentEditorActionsComponent = memo (
42+ ( {
43+ isEmpty : _isEmpty ,
44+ comment,
45+ isEditing,
46+ threadStore,
47+ onReactionSelect,
48+ onEditSubmit,
49+ onEditCancel,
50+ onEmojiPickerOpenChange,
51+ Components,
52+ dict,
53+ } : CommentEditorActionsProps ) => {
54+ const canAddReaction = threadStore . auth . canAddReaction ( comment ) ;
55+
56+ return (
57+ < >
58+ { comment . reactions . length > 0 && ! isEditing && (
59+ < Components . Generic . Badge . Group
60+ className = { mergeCSSClasses (
61+ "bn-badge-group" ,
62+ "bn-comment-reactions" ,
63+ ) }
64+ >
65+ { comment . reactions . map ( ( reaction ) => (
66+ < ReactionBadge
67+ key = { reaction . emoji }
68+ comment = { comment }
69+ emoji = { reaction . emoji }
70+ onReactionSelect = { onReactionSelect }
71+ />
72+ ) ) }
73+ { canAddReaction && (
74+ < EmojiPicker
75+ onEmojiSelect = { ( emoji : { native : string } ) =>
76+ onReactionSelect ( emoji . native )
77+ }
78+ onOpenChange = { onEmojiPickerOpenChange }
79+ >
80+ < Components . Generic . Badge . Root
81+ className = { mergeCSSClasses (
82+ "bn-badge" ,
83+ "bn-comment-add-reaction" ,
84+ ) }
85+ text = { "+" }
86+ icon = { < RiEmotionLine size = { 16 } /> }
87+ mainTooltip = { dict . comments . actions . add_reaction }
88+ />
89+ </ EmojiPicker >
90+ ) }
91+ </ Components . Generic . Badge . Group >
92+ ) }
93+ { isEditing && (
94+ < Components . Generic . Toolbar . Root
95+ variant = "action-toolbar"
96+ className = { mergeCSSClasses (
97+ "bn-action-toolbar" ,
98+ "bn-comment-actions" ,
99+ ) }
100+ >
101+ < Components . Generic . Toolbar . Button
102+ mainTooltip = { dict . comments . save_button_text }
103+ variant = "compact"
104+ onClick = { onEditSubmit }
105+ isDisabled = { _isEmpty }
106+ >
107+ { dict . comments . save_button_text }
108+ </ Components . Generic . Toolbar . Button >
109+ < Components . Generic . Toolbar . Button
110+ className = { "bn-button" }
111+ mainTooltip = { dict . comments . cancel_button_text }
112+ variant = "compact"
113+ onClick = { onEditCancel }
114+ >
115+ { dict . comments . cancel_button_text }
116+ </ Components . Generic . Toolbar . Button >
117+ </ Components . Generic . Toolbar . Root >
118+ ) }
119+ </ >
120+ ) ;
121+ } ,
122+ ) ;
123+
26124export type CommentProps = {
27125 comment : CommentData ;
28126 thread : ThreadData ;
@@ -130,88 +228,6 @@ export const Comment = ({
130228
131229 const user = useUser ( comment . userId ) ;
132230
133- const CommentEditorActions = useCallback (
134- ( { isEmpty } : { isFocused : boolean ; isEmpty : boolean } ) => {
135- const canAddReaction = threadStore . auth . canAddReaction ( comment ) ;
136-
137- return (
138- < >
139- { comment . reactions . length > 0 && ! isEditing && (
140- < Components . Generic . Badge . Group
141- className = { mergeCSSClasses (
142- "bn-badge-group" ,
143- "bn-comment-reactions" ,
144- ) }
145- >
146- { comment . reactions . map ( ( reaction ) => (
147- < ReactionBadge
148- key = { reaction . emoji }
149- comment = { comment }
150- emoji = { reaction . emoji }
151- onReactionSelect = { onReactionSelect }
152- />
153- ) ) }
154- { canAddReaction && (
155- < EmojiPicker
156- onEmojiSelect = { ( emoji : { native : string } ) =>
157- onReactionSelect ( emoji . native )
158- }
159- onOpenChange = { setEmojiPickerOpen }
160- >
161- < Components . Generic . Badge . Root
162- className = { mergeCSSClasses (
163- "bn-badge" ,
164- "bn-comment-add-reaction" ,
165- ) }
166- text = { "+" }
167- icon = { < RiEmotionLine size = { 16 } /> }
168- mainTooltip = { dict . comments . actions . add_reaction }
169- />
170- </ EmojiPicker >
171- ) }
172- </ Components . Generic . Badge . Group >
173- ) }
174- { isEditing && (
175- < Components . Generic . Toolbar . Root
176- variant = "action-toolbar"
177- className = { mergeCSSClasses (
178- "bn-action-toolbar" ,
179- "bn-comment-actions" ,
180- ) }
181- >
182- < Components . Generic . Toolbar . Button
183- mainTooltip = { dict . comments . save_button_text }
184- variant = "compact"
185- onClick = { onEditSubmit }
186- isDisabled = { isEmpty }
187- >
188- { dict . comments . save_button_text }
189- </ Components . Generic . Toolbar . Button >
190- < Components . Generic . Toolbar . Button
191- className = { "bn-button" }
192- mainTooltip = { dict . comments . cancel_button_text }
193- variant = "compact"
194- onClick = { onEditCancel }
195- >
196- { dict . comments . cancel_button_text }
197- </ Components . Generic . Toolbar . Button >
198- </ Components . Generic . Toolbar . Root >
199- ) }
200- </ >
201- ) ;
202- } ,
203- [
204- comment ,
205- isEditing ,
206- threadStore ,
207- onReactionSelect ,
208- onEditSubmit ,
209- onEditCancel ,
210- Components ,
211- dict ,
212- ] ,
213- ) ;
214-
215231 if ( ! comment . body ) {
216232 return null ;
217233 }
@@ -331,7 +347,21 @@ export const Comment = ({
331347 editable = { isEditing }
332348 actions = {
333349 comment . reactions . length > 0 || isEditing
334- ? CommentEditorActions
350+ ? ( { isFocused, isEmpty } ) => (
351+ < CommentEditorActionsComponent
352+ isFocused = { isFocused }
353+ isEmpty = { isEmpty }
354+ comment = { comment }
355+ isEditing = { isEditing }
356+ threadStore = { threadStore }
357+ onReactionSelect = { onReactionSelect }
358+ onEditSubmit = { onEditSubmit }
359+ onEditCancel = { onEditCancel }
360+ onEmojiPickerOpenChange = { setEmojiPickerOpen }
361+ Components = { Components }
362+ dict = { dict }
363+ />
364+ )
335365 : undefined
336366 }
337367 />
0 commit comments