@@ -6,7 +6,7 @@ const mdToFormattingType: Record<string, MessageInputFormattingType> = {
6
6
'**' : 'bold' ,
7
7
'*' : 'italics' ,
8
8
'~~' : 'strikethrough' ,
9
- '`` ' : 'code' ,
9
+ '`' : 'code' ,
10
10
}
11
11
12
12
export const formattingTypeToMarkdown : Record < MessageInputFormattingType , string > = {
@@ -47,29 +47,36 @@ export const useMessageInputCompositionControls = () => {
47
47
const textarea = textareaRef . current ;
48
48
if ( ! textarea ) return ;
49
49
50
+ let newSelection ;
50
51
const { activeFormatting} = customDataManager . customComposerData ;
51
52
if ( ! activeFormatting ) {
52
53
textComposer . wrapSelection ( { head : wrappingMarkdown , tail : wrappingMarkdown } ) ;
53
54
customDataManager . setCustomData ( { activeFormatting : mdToFormattingType [ wrappingMarkdown ] } ) ;
54
- textarea . selectionStart = textComposer . selection . start ;
55
- textarea . selectionEnd = textComposer . selection . end ;
56
- textarea . focus ( ) ;
57
- return ;
58
- }
59
- const activeMarkdown = formattingTypeToMarkdown [ activeFormatting ] ;
60
- const newSelection = {
61
- start : textComposer . selection . start + activeMarkdown . length ,
62
- end : textComposer . selection . end + + activeMarkdown . length ,
63
- } ;
64
- textarea . selectionStart = newSelection . start ;
65
- textarea . selectionEnd = newSelection . end ;
66
- if ( wrappingMarkdown === activeMarkdown ) {
67
- customDataManager . setCustomData ( { activeFormatting : null } ) ;
55
+ newSelection = {
56
+ start :textComposer . selection . start ,
57
+ end : textComposer . selection . end ,
58
+ } ;
68
59
} else {
69
- customDataManager . setCustomData ( { activeFormatting : mdToFormattingType [ wrappingMarkdown ] } ) ;
70
- textComposer . wrapSelection ( { head : wrappingMarkdown , selection : newSelection , tail : wrappingMarkdown } ) ;
60
+ const activeMarkdown = formattingTypeToMarkdown [ activeFormatting ] ;
61
+ newSelection = {
62
+ start : textComposer . selection . start + activeMarkdown . length + wrappingMarkdown . length ,
63
+ end : textComposer . selection . end + + activeMarkdown . length + wrappingMarkdown . length ,
64
+ } ;
65
+ if ( wrappingMarkdown === activeMarkdown ) {
66
+ customDataManager . setCustomData ( { activeFormatting : null } ) ;
67
+ } else {
68
+ customDataManager . setCustomData ( { activeFormatting : mdToFormattingType [ wrappingMarkdown ] } ) ;
69
+ textComposer . wrapSelection ( { head : wrappingMarkdown , selection : newSelection , tail : wrappingMarkdown } ) ;
70
+ }
71
71
}
72
72
textarea . focus ( ) ;
73
+ /**
74
+ * Some browsers (especially Chrome/Edge/WebKit) will move the caret to the end of the text after focus as part of their default focus-handling.
75
+ * That happens after our JS runs, so it overwrites the position we set - browser invokes the event with the selection at the end of the textarea string
76
+ */
77
+ setTimeout ( ( ) => {
78
+ textarea . setSelectionRange ( newSelection . start , newSelection . end )
79
+ } , 0 ) ;
73
80
} , [ customDataManager , textareaRef , textComposer ] )
74
81
75
82
const formatter = useMemo < Record < MessageInputFormattingType , ( ) => void > > ( ( ) => ( {
0 commit comments