@@ -21,7 +21,49 @@ export function FormattingToolbar({ editor }: FormattingToolbarProps) {
2121 const toggleUnderline = ( ) => editor . chain ( ) . focus ( ) . toggleUnderline ( ) . run ( ) ;
2222 const toggleStrike = ( ) => editor . chain ( ) . focus ( ) . toggleStrike ( ) . run ( ) ;
2323 const toggleCode = ( ) => editor . chain ( ) . focus ( ) . toggleCode ( ) . run ( ) ;
24- const toggleCodeBlock = ( ) => editor . chain ( ) . focus ( ) . toggleCodeBlock ( ) . run ( ) ;
24+ const toggleCodeBlock = ( ) => {
25+ const { from } = editor . state . selection ;
26+
27+ // Check if we're in a code block already
28+ if ( editor . isActive ( "codeBlock" ) ) {
29+ // If we're in a code block, convert back to paragraph
30+ editor . chain ( ) . focus ( ) . toggleCodeBlock ( ) . run ( ) ;
31+ } else {
32+ // Check if current node contains mentions
33+ const $from = editor . state . doc . resolve ( from ) ;
34+ const currentNode = $from . parent ;
35+ let hasMentions = false ;
36+
37+ // Check if the current paragraph has mention nodes
38+ if ( currentNode . content ) {
39+ currentNode . content . forEach ( ( node ) => {
40+ if ( node . type . name === "mention" ) {
41+ hasMentions = true ;
42+ }
43+ } ) ;
44+ }
45+
46+ if ( hasMentions ) {
47+ // If there are mentions, create code block on a new line after current paragraph
48+ const endOfParagraph = $from . end ( $from . depth ) ;
49+
50+ editor
51+ . chain ( )
52+ . focus ( )
53+ . setTextSelection ( endOfParagraph )
54+ . insertContent ( [
55+ {
56+ type : "codeBlock" ,
57+ content : [ { type : "text" , text : "" } ] ,
58+ } ,
59+ ] )
60+ . run ( ) ;
61+ } else {
62+ // No mentions, use the normal toggle
63+ editor . chain ( ) . focus ( ) . toggleCodeBlock ( ) . run ( ) ;
64+ }
65+ }
66+ } ;
2567 const toggleBlockquote = ( ) =>
2668 editor . chain ( ) . focus ( ) . toggleBlockquote ( ) . run ( ) ;
2769 const toggleBulletList = ( ) =>
@@ -37,7 +79,30 @@ export function FormattingToolbar({ editor }: FormattingToolbarProps) {
3779 } ;
3880
3981 const setHeading = ( level : 1 | 2 | 3 | 4 | 5 | 6 ) => {
40- editor . chain ( ) . focus ( ) . toggleHeading ( { level } ) . run ( ) ;
82+ const { from, to } = editor . state . selection ;
83+
84+ // If there's a text selection, wrap it in a new paragraph and convert to heading
85+ if ( from !== to ) {
86+ const selectedText = editor . state . doc . textBetween ( from , to ) ;
87+ editor
88+ . chain ( )
89+ . focus ( )
90+ . deleteSelection ( )
91+ . insertContent ( [
92+ {
93+ type : "heading" ,
94+ attrs : { level } ,
95+ content : [ { type : "text" , text : selectedText } ] ,
96+ } ,
97+ {
98+ type : "paragraph" ,
99+ } ,
100+ ] )
101+ . run ( ) ;
102+ } else {
103+ // No selection, toggle heading for current block
104+ editor . chain ( ) . focus ( ) . toggleHeading ( { level } ) . run ( ) ;
105+ }
41106 } ;
42107
43108 const getCurrentHeading = ( ) => {
@@ -70,7 +135,29 @@ export function FormattingToolbar({ editor }: FormattingToolbarProps) {
70135 value = { getCurrentHeading ( ) }
71136 onValueChange = { ( value ) => {
72137 if ( value === "paragraph" ) {
73- editor . chain ( ) . focus ( ) . setParagraph ( ) . run ( ) ;
138+ const { from, to } = editor . state . selection ;
139+
140+ // If there's a text selection, wrap it in a new paragraph
141+ if ( from !== to ) {
142+ const selectedText = editor . state . doc . textBetween ( from , to ) ;
143+ editor
144+ . chain ( )
145+ . focus ( )
146+ . deleteSelection ( )
147+ . insertContent ( [
148+ {
149+ type : "paragraph" ,
150+ content : [ { type : "text" , text : selectedText } ] ,
151+ } ,
152+ {
153+ type : "paragraph" ,
154+ } ,
155+ ] )
156+ . run ( ) ;
157+ } else {
158+ // No selection, set current block to paragraph
159+ editor . chain ( ) . focus ( ) . setParagraph ( ) . run ( ) ;
160+ }
74161 } else {
75162 setHeading ( parseInt ( value , 10 ) as 1 | 2 | 3 | 4 | 5 | 6 ) ;
76163 }
0 commit comments