@@ -12,6 +12,7 @@ import ChevronDown from "lucide-react/dist/esm/icons/chevron-down";
1212import ChevronUp from "lucide-react/dist/esm/icons/chevron-up" ;
1313import Mic from "lucide-react/dist/esm/icons/mic" ;
1414import Square from "lucide-react/dist/esm/icons/square" ;
15+ import X from "lucide-react/dist/esm/icons/x" ;
1516import Brain from "lucide-react/dist/esm/icons/brain" ;
1617import GitFork from "lucide-react/dist/esm/icons/git-fork" ;
1718import PlusCircle from "lucide-react/dist/esm/icons/plus-circle" ;
@@ -46,6 +47,7 @@ type ComposerInputProps = {
4647 dictationLevel ?: number ;
4748 dictationEnabled ?: boolean ;
4849 onToggleDictation ?: ( ) => void ;
50+ onCancelDictation ?: ( ) => void ;
4951 onOpenDictationSettings ?: ( ) => void ;
5052 dictationError ?: string | null ;
5153 onDismissDictationError ?: ( ) => void ;
@@ -148,6 +150,7 @@ export function ComposerInput({
148150 dictationLevel = 0 ,
149151 dictationEnabled = false ,
150152 onToggleDictation,
153+ onCancelDictation,
151154 onOpenDictationSettings,
152155 dictationError = null ,
153156 onDismissDictationError,
@@ -331,27 +334,39 @@ export function ComposerInput({
331334 }
332335 } , [ canStop , onSend , onStop ] ) ;
333336 const isDictating = dictationState === "listening" ;
337+ const isDictationProcessing = dictationState === "processing" ;
334338 const isDictationBusy = dictationState !== "idle" ;
335339 const allowOpenDictationSettings = Boolean (
336- onOpenDictationSettings && ! dictationEnabled && ! disabled ,
340+ onOpenDictationSettings && ! dictationEnabled && ! disabled && ! isDictationProcessing ,
337341 ) ;
338342 const micDisabled =
339- disabled || dictationState === "processing" || ! dictationEnabled || ! onToggleDictation ;
343+ disabled ||
344+ ( ! allowOpenDictationSettings &&
345+ ( isDictationProcessing
346+ ? ! onCancelDictation
347+ : ! dictationEnabled || ! onToggleDictation ) ) ;
340348 const micAriaLabel = allowOpenDictationSettings
341349 ? "Open dictation settings"
342- : dictationState === "processing"
343- ? "Dictation processing "
350+ : isDictationProcessing
351+ ? "Cancel transcription "
344352 : isDictating
345353 ? "Stop dictation"
346354 : "Start dictation" ;
347355 const micTitle = allowOpenDictationSettings
348356 ? "Dictation disabled. Open settings"
349- : dictationState === "processing"
350- ? "Processing dictation "
357+ : isDictationProcessing
358+ ? "Cancel transcription "
351359 : isDictating
352360 ? "Stop dictation"
353361 : "Start dictation" ;
354362 const handleMicClick = useCallback ( ( ) => {
363+ if ( isDictationProcessing ) {
364+ if ( disabled || ! onCancelDictation ) {
365+ return ;
366+ }
367+ onCancelDictation ( ) ;
368+ return ;
369+ }
355370 if ( allowOpenDictationSettings ) {
356371 onOpenDictationSettings ?.( ) ;
357372 return ;
@@ -361,7 +376,10 @@ export function ComposerInput({
361376 }
362377 onToggleDictation ( ) ;
363378 } , [
379+ disabled ,
380+ isDictationProcessing ,
364381 allowOpenDictationSettings ,
382+ onCancelDictation ,
365383 micDisabled ,
366384 onOpenDictationSettings ,
367385 onToggleDictation ,
@@ -478,15 +496,19 @@ export function ComposerInput({
478496 { isExpanded ? "Collapse input" : "Expand input" }
479497 </ PopoverMenuItem >
480498 ) }
481- { ( onToggleDictation || onOpenDictationSettings ) && (
499+ { ( onToggleDictation || onOpenDictationSettings || onCancelDictation ) && (
482500 < PopoverMenuItem
483501 onClick = { handleMobileDictationClick }
484- disabled = {
485- disabled ||
486- dictationState === "processing" ||
487- ( ! onToggleDictation && ! allowOpenDictationSettings )
502+ disabled = { micDisabled }
503+ icon = {
504+ isDictationProcessing ? (
505+ < X size = { 14 } />
506+ ) : isDictating ? (
507+ < Square size = { 14 } />
508+ ) : (
509+ < Mic size = { 14 } />
510+ )
488511 }
489- icon = { isDictating ? < Square size = { 14 } /> : < Mic size = { 14 } /> }
490512 >
491513 { micAriaLabel }
492514 </ PopoverMenuItem >
@@ -685,19 +707,21 @@ export function ComposerInput({
685707 < button
686708 className = { `composer-action composer-action--mic${
687709 isDictationBusy ? " is-active" : ""
688- } ${ dictationState === "processing" ? " is-processing" : "" } ${
710+ } ${ isDictationProcessing ? " is-processing is-stop " : "" } ${
689711 micDisabled ? " is-disabled" : ""
690712 } `}
691713 onClick = { handleMicClick }
692- disabled = {
693- disabled ||
694- dictationState === "processing" ||
695- ( ! onToggleDictation && ! allowOpenDictationSettings )
696- }
714+ disabled = { micDisabled }
697715 aria-label = { micAriaLabel }
698716 title = { micTitle }
699717 >
700- { isDictating ? < Square aria-hidden /> : < Mic aria-hidden /> }
718+ { isDictationProcessing ? (
719+ < X aria-hidden />
720+ ) : isDictating ? (
721+ < Square aria-hidden />
722+ ) : (
723+ < Mic aria-hidden />
724+ ) }
701725 </ button >
702726 < button
703727 className = { `composer-action${ canStop ? " is-stop" : " is-send" } ${
0 commit comments