@archbase/components 3.0.25 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/buttons/ArchbaseSpeedDial.d.ts +59 -0
- package/dist/buttons/index.d.ts +2 -0
- package/dist/charts/ArchbaseArcGauge.d.ts +55 -0
- package/dist/charts/ArchbaseGantt.d.ts +70 -0
- package/dist/charts/ArchbaseLinearGauge.d.ts +55 -0
- package/dist/charts/ArchbaseResourceTimeline.d.ts +61 -0
- package/dist/charts/ArchbaseSparkline.d.ts +45 -0
- package/dist/charts/index.d.ts +10 -0
- package/dist/containers/ArchbaseExpansionPanel.d.ts +60 -0
- package/dist/containers/ArchbaseFloatingPanel.d.ts +91 -0
- package/dist/containers/index.d.ts +4 -0
- package/dist/datagrid/export/ArchbaseDataGridExcelExport.d.ts +67 -0
- package/dist/datagrid/export/index.d.ts +2 -0
- package/dist/datagrid/index.d.ts +1 -0
- package/dist/display/ArchbaseAnimationWrapper.d.ts +73 -0
- package/dist/display/ArchbaseBarcodeGenerator.d.ts +50 -0
- package/dist/display/ArchbaseCarousel.d.ts +100 -0
- package/dist/display/ArchbaseCodeViewer.d.ts +63 -0
- package/dist/display/ArchbaseDiffViewer.d.ts +41 -0
- package/dist/display/ArchbaseJsonTree.d.ts +34 -0
- package/dist/display/ArchbaseLightbox.d.ts +89 -0
- package/dist/display/ArchbaseMarquee.d.ts +46 -0
- package/dist/display/ArchbasePhotoAlbum.d.ts +58 -0
- package/dist/display/ArchbaseQRCode.d.ts +44 -0
- package/dist/display/ArchbaseTooltipRich.d.ts +82 -0
- package/dist/display/ArchbaseVirtualList.d.ts +116 -0
- package/dist/display/index.d.ts +24 -0
- package/dist/editors/ArchbaseAIPromptInput.d.ts +69 -0
- package/dist/editors/ArchbaseAsyncMultiSelect.d.ts +1 -1
- package/dist/editors/ArchbaseAsyncSelect.d.ts +1 -1
- package/dist/editors/ArchbaseBarcodeScanner.d.ts +63 -0
- package/dist/editors/ArchbaseCepInput.d.ts +26 -0
- package/dist/editors/ArchbaseColorGradientPicker.d.ts +80 -0
- package/dist/editors/ArchbaseCpfCnpjInput.d.ts +21 -0
- package/dist/editors/ArchbaseCurrencyInput.d.ts +25 -0
- package/dist/editors/ArchbaseDualListbox.d.ts +61 -0
- package/dist/editors/ArchbaseInPlaceEditor.d.ts +67 -0
- package/dist/editors/ArchbaseLightGrid.d.ts +56 -0
- package/dist/editors/ArchbaseMentionInput.d.ts +75 -0
- package/dist/editors/ArchbaseMultiEmail.d.ts +53 -0
- package/dist/editors/ArchbaseMultiViewCalendar.d.ts +47 -0
- package/dist/editors/ArchbaseNumberStepper.d.ts +66 -0
- package/dist/editors/ArchbaseOTPInput.d.ts +27 -0
- package/dist/editors/ArchbasePhoneInput.d.ts +52 -0
- package/dist/editors/ArchbaseRangeSlider.d.ts +22 -0
- package/dist/editors/ArchbaseSignaturePad.d.ts +60 -0
- package/dist/editors/ArchbaseSpeechToTextInput.d.ts +106 -0
- package/dist/editors/ArchbaseSpreadsheet.d.ts +56 -0
- package/dist/editors/ArchbaseTagInput.d.ts +55 -0
- package/dist/editors/index.d.ts +40 -0
- package/dist/feedback/ArchbaseChunkProgressBar.d.ts +35 -0
- package/dist/feedback/ArchbaseRipple.d.ts +43 -0
- package/dist/feedback/ArchbaseSkeleton.d.ts +115 -0
- package/dist/feedback/index.d.ts +6 -0
- package/dist/filters/ArchbaseColumnSelector.d.ts +38 -0
- package/dist/filters/index.d.ts +2 -0
- package/dist/forms/ArchbaseFieldArray.d.ts +80 -0
- package/dist/forms/ArchbaseFormWizard.d.ts +73 -0
- package/dist/forms/ArchbaseStepper.d.ts +51 -0
- package/dist/forms/index.d.ts +8 -0
- package/dist/forms/useArchbaseFormWizard.d.ts +74 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useArchbaseConfirm.d.ts +59 -0
- package/dist/image/editor/index.d.ts +43 -4
- package/dist/image/index.d.ts +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22510 -13820
- package/dist/list/ArchbaseTreeList.d.ts +76 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/navigation/ArchbaseActionSheet.d.ts +70 -0
- package/dist/navigation/ArchbaseAppBar.d.ts +63 -0
- package/dist/navigation/ArchbaseBottomNavigation.d.ts +61 -0
- package/dist/navigation/ArchbaseContextMenu.d.ts +76 -0
- package/dist/navigation/ArchbaseKeyboardShortcuts.d.ts +85 -0
- package/dist/navigation/ArchbaseSpotlight.d.ts +69 -0
- package/dist/navigation/index.d.ts +12 -0
- package/dist/notification/ArchbaseNotificationCenter.d.ts +56 -0
- package/dist/notification/index.d.ts +2 -0
- package/dist/onboarding/ArchbaseOnboardingTour.d.ts +27 -76
- package/dist/viewers/ArchbaseDocViewer.d.ts +40 -0
- package/dist/viewers/ArchbasePdfBuilder.d.ts +53 -0
- package/dist/viewers/ArchbaseXmlViewer.d.ts +36 -0
- package/dist/viewers/index.d.ts +6 -0
- package/package.json +41 -18
- package/src/buttons/ArchbaseSpeedDial.tsx +282 -0
- package/src/buttons/index.ts +3 -0
- package/src/charts/ArchbaseArcGauge.tsx +325 -0
- package/src/charts/ArchbaseGantt.tsx +494 -0
- package/src/charts/ArchbaseLinearGauge.tsx +288 -0
- package/src/charts/ArchbaseResourceTimeline.tsx +433 -0
- package/src/charts/ArchbaseSparkline.tsx +193 -0
- package/src/charts/index.ts +20 -1
- package/src/containers/ArchbaseExpansionPanel.tsx +208 -0
- package/src/containers/ArchbaseFloatingPanel.tsx +448 -0
- package/src/containers/index.ts +17 -0
- package/src/datagrid/components/pagination/grid-pagination.tsx +2 -2
- package/src/datagrid/export/ArchbaseDataGridExcelExport.tsx +293 -0
- package/src/datagrid/export/index.ts +8 -0
- package/src/datagrid/index.tsx +2 -0
- package/src/display/ArchbaseAnimationWrapper.tsx +272 -0
- package/src/display/ArchbaseBarcodeGenerator.tsx +303 -0
- package/src/display/ArchbaseCarousel.tsx +679 -0
- package/src/display/ArchbaseCodeViewer.tsx +271 -0
- package/src/display/ArchbaseDiffViewer.tsx +108 -0
- package/src/display/ArchbaseJsonTree.tsx +150 -0
- package/src/display/ArchbaseLightbox.tsx +279 -0
- package/src/display/ArchbaseMarquee.tsx +268 -0
- package/src/display/ArchbasePhotoAlbum.tsx +415 -0
- package/src/display/ArchbaseQRCode.tsx +137 -0
- package/src/display/ArchbaseTooltipRich.tsx +317 -0
- package/src/display/ArchbaseVirtualList.tsx +618 -0
- package/src/display/index.ts +94 -1
- package/src/editors/ArchbaseAIPromptInput.tsx +432 -0
- package/src/editors/ArchbaseBarcodeScanner.tsx +570 -0
- package/src/editors/ArchbaseCepInput.tsx +173 -0
- package/src/editors/ArchbaseColorGradientPicker.tsx +460 -0
- package/src/editors/ArchbaseCpfCnpjInput.tsx +193 -0
- package/src/editors/ArchbaseCurrencyInput.tsx +100 -0
- package/src/editors/ArchbaseDualListbox.tsx +671 -0
- package/src/editors/ArchbaseInPlaceEditor.tsx +406 -0
- package/src/editors/ArchbaseLightGrid.tsx +538 -0
- package/src/editors/ArchbaseMentionInput.tsx +384 -0
- package/src/editors/ArchbaseMultiEmail.tsx +367 -0
- package/src/editors/ArchbaseMultiViewCalendar.tsx +439 -0
- package/src/editors/ArchbaseNumberStepper.tsx +219 -0
- package/src/editors/ArchbaseOTPInput.tsx +133 -0
- package/src/editors/ArchbaseOperationHoursEditor.tsx +1 -1
- package/src/editors/ArchbasePhoneInput.tsx +355 -0
- package/src/editors/ArchbaseRangeSlider.tsx +109 -0
- package/src/editors/ArchbaseSignaturePad.tsx +425 -0
- package/src/editors/ArchbaseSpeechToTextInput.tsx +444 -0
- package/src/editors/ArchbaseSpreadsheet.tsx +388 -0
- package/src/editors/ArchbaseTagInput.tsx +326 -0
- package/src/editors/index.tsx +92 -0
- package/src/feedback/ArchbaseChunkProgressBar.tsx +156 -0
- package/src/feedback/ArchbaseRipple.tsx +278 -0
- package/src/feedback/ArchbaseSkeleton.tsx +419 -0
- package/src/feedback/index.ts +22 -1
- package/src/filters/ArchbaseColumnSelector.tsx +268 -0
- package/src/filters/index.ts +2 -0
- package/src/forms/ArchbaseFieldArray.tsx +305 -0
- package/src/forms/ArchbaseFormWizard.tsx +284 -0
- package/src/forms/ArchbaseStepper.tsx +137 -0
- package/src/forms/index.ts +24 -2
- package/src/forms/useArchbaseFormWizard.ts +283 -0
- package/src/hooks/index.ts +12 -0
- package/src/hooks/useArchbaseConfirm.ts +293 -0
- package/src/image/editor/functions/image-processing.ts +5 -0
- package/src/image/editor/index.tsx +305 -391
- package/src/image/index.ts +1 -0
- package/src/index.ts +3 -0
- package/src/list/ArchbaseTreeList.tsx +422 -0
- package/src/list/index.ts +3 -0
- package/src/navigation/ArchbaseActionSheet.tsx +301 -0
- package/src/navigation/ArchbaseAppBar.tsx +233 -0
- package/src/navigation/ArchbaseBottomNavigation.tsx +243 -0
- package/src/navigation/ArchbaseContextMenu.tsx +298 -0
- package/src/navigation/ArchbaseKeyboardShortcuts.tsx +472 -0
- package/src/navigation/ArchbaseSpotlight.tsx +483 -0
- package/src/navigation/index.ts +48 -1
- package/src/notification/ArchbaseNotificationCenter.tsx +502 -0
- package/src/notification/index.ts +2 -0
- package/src/onboarding/ArchbaseOnboardingTour.tsx +229 -102
- package/src/viewers/ArchbaseDocViewer.tsx +584 -0
- package/src/viewers/ArchbasePdfBuilder.tsx +291 -0
- package/src/viewers/ArchbaseXmlViewer.tsx +142 -0
- package/src/viewers/index.ts +12 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import React, { useCallback, useState, useEffect, useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
TextInput,
|
|
4
|
+
TextInputProps,
|
|
5
|
+
Textarea,
|
|
6
|
+
TextareaProps,
|
|
7
|
+
ActionIcon,
|
|
8
|
+
Tooltip,
|
|
9
|
+
Box,
|
|
10
|
+
Text,
|
|
11
|
+
Loader,
|
|
12
|
+
} from '@mantine/core';
|
|
13
|
+
import { IconMicrophone, IconMicrophoneOff, IconPlayerStop } from '@tabler/icons-react';
|
|
14
|
+
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Types
|
|
17
|
+
// =============================================================================
|
|
18
|
+
|
|
19
|
+
interface SpeechRecognitionEvent {
|
|
20
|
+
resultIndex: number;
|
|
21
|
+
results: SpeechRecognitionResultList;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface SpeechRecognitionErrorEvent {
|
|
25
|
+
error: string;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface SpeechRecognition extends EventTarget {
|
|
30
|
+
continuous: boolean;
|
|
31
|
+
interimResults: boolean;
|
|
32
|
+
lang: string;
|
|
33
|
+
start: () => void;
|
|
34
|
+
stop: () => void;
|
|
35
|
+
abort: () => void;
|
|
36
|
+
onresult: ((event: SpeechRecognitionEvent) => void) | null;
|
|
37
|
+
onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;
|
|
38
|
+
onend: (() => void) | null;
|
|
39
|
+
onstart: (() => void) | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare global {
|
|
43
|
+
interface Window {
|
|
44
|
+
SpeechRecognition: new () => SpeechRecognition;
|
|
45
|
+
webkitSpeechRecognition: new () => SpeechRecognition;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UseArchbaseSpeechToTextOptions {
|
|
50
|
+
/** Idioma (padrão: pt-BR) */
|
|
51
|
+
lang?: string;
|
|
52
|
+
/** Modo contínuo */
|
|
53
|
+
continuous?: boolean;
|
|
54
|
+
/** Resultados intermediários */
|
|
55
|
+
interimResults?: boolean;
|
|
56
|
+
/** Callback ao obter transcrição */
|
|
57
|
+
onTranscript?: (transcript: string, isFinal: boolean) => void;
|
|
58
|
+
/** Callback em caso de erro */
|
|
59
|
+
onError?: (error: string) => void;
|
|
60
|
+
/** Callback ao iniciar */
|
|
61
|
+
onStart?: () => void;
|
|
62
|
+
/** Callback ao parar */
|
|
63
|
+
onEnd?: () => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface UseArchbaseSpeechToTextReturn {
|
|
67
|
+
/** Se está gravando */
|
|
68
|
+
isListening: boolean;
|
|
69
|
+
/** Transcrição atual */
|
|
70
|
+
transcript: string;
|
|
71
|
+
/** Se o browser suporta */
|
|
72
|
+
isSupported: boolean;
|
|
73
|
+
/** Último erro */
|
|
74
|
+
error: string | null;
|
|
75
|
+
/** Iniciar gravação */
|
|
76
|
+
start: () => void;
|
|
77
|
+
/** Parar gravação */
|
|
78
|
+
stop: () => void;
|
|
79
|
+
/** Limpar transcrição */
|
|
80
|
+
clear: () => void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// =============================================================================
|
|
84
|
+
// Hook useArchbaseSpeechToText
|
|
85
|
+
// =============================================================================
|
|
86
|
+
|
|
87
|
+
export function useArchbaseSpeechToText({
|
|
88
|
+
lang = 'pt-BR',
|
|
89
|
+
continuous = false,
|
|
90
|
+
interimResults = true,
|
|
91
|
+
onTranscript,
|
|
92
|
+
onError,
|
|
93
|
+
onStart,
|
|
94
|
+
onEnd,
|
|
95
|
+
}: UseArchbaseSpeechToTextOptions = {}): UseArchbaseSpeechToTextReturn {
|
|
96
|
+
const [isListening, setIsListening] = useState(false);
|
|
97
|
+
const [transcript, setTranscript] = useState('');
|
|
98
|
+
const [error, setError] = useState<string | null>(null);
|
|
99
|
+
const recognitionRef = useRef<SpeechRecognition | null>(null);
|
|
100
|
+
|
|
101
|
+
const isSupported = typeof window !== 'undefined' &&
|
|
102
|
+
(!!window.SpeechRecognition || !!window.webkitSpeechRecognition);
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!isSupported) return;
|
|
106
|
+
|
|
107
|
+
const SpeechRecognitionClass = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
108
|
+
const recognition = new SpeechRecognitionClass();
|
|
109
|
+
|
|
110
|
+
recognition.continuous = continuous;
|
|
111
|
+
recognition.interimResults = interimResults;
|
|
112
|
+
recognition.lang = lang;
|
|
113
|
+
|
|
114
|
+
recognition.onresult = (event: SpeechRecognitionEvent) => {
|
|
115
|
+
let finalTranscript = '';
|
|
116
|
+
let interimTranscript = '';
|
|
117
|
+
|
|
118
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
119
|
+
const result = event.results[i];
|
|
120
|
+
if (result.isFinal) {
|
|
121
|
+
finalTranscript += result[0].transcript;
|
|
122
|
+
} else {
|
|
123
|
+
interimTranscript += result[0].transcript;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const currentTranscript = finalTranscript || interimTranscript;
|
|
128
|
+
setTranscript(prev => finalTranscript ? prev + finalTranscript : prev);
|
|
129
|
+
onTranscript?.(currentTranscript, !!finalTranscript);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
recognition.onerror = (event: SpeechRecognitionErrorEvent) => {
|
|
133
|
+
const errorMessage = getErrorMessage(event.error);
|
|
134
|
+
setError(errorMessage);
|
|
135
|
+
onError?.(errorMessage);
|
|
136
|
+
setIsListening(false);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
recognition.onend = () => {
|
|
140
|
+
setIsListening(false);
|
|
141
|
+
onEnd?.();
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
recognition.onstart = () => {
|
|
145
|
+
setIsListening(true);
|
|
146
|
+
setError(null);
|
|
147
|
+
onStart?.();
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
recognitionRef.current = recognition;
|
|
151
|
+
|
|
152
|
+
return () => {
|
|
153
|
+
recognition.abort();
|
|
154
|
+
};
|
|
155
|
+
}, [lang, continuous, interimResults, onTranscript, onError, onStart, onEnd, isSupported]);
|
|
156
|
+
|
|
157
|
+
const start = useCallback(() => {
|
|
158
|
+
if (!recognitionRef.current || isListening) return;
|
|
159
|
+
setTranscript('');
|
|
160
|
+
setError(null);
|
|
161
|
+
try {
|
|
162
|
+
recognitionRef.current.start();
|
|
163
|
+
} catch (e) {
|
|
164
|
+
// Already started
|
|
165
|
+
}
|
|
166
|
+
}, [isListening]);
|
|
167
|
+
|
|
168
|
+
const stop = useCallback(() => {
|
|
169
|
+
if (!recognitionRef.current || !isListening) return;
|
|
170
|
+
recognitionRef.current.stop();
|
|
171
|
+
}, [isListening]);
|
|
172
|
+
|
|
173
|
+
const clear = useCallback(() => {
|
|
174
|
+
setTranscript('');
|
|
175
|
+
setError(null);
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
isListening,
|
|
180
|
+
transcript,
|
|
181
|
+
isSupported,
|
|
182
|
+
error,
|
|
183
|
+
start,
|
|
184
|
+
stop,
|
|
185
|
+
clear,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getErrorMessage(error: string): string {
|
|
190
|
+
const messages: Record<string, string> = {
|
|
191
|
+
'no-speech': 'Nenhuma fala detectada',
|
|
192
|
+
'audio-capture': 'Microfone não disponível',
|
|
193
|
+
'not-allowed': 'Permissão de microfone negada',
|
|
194
|
+
'network': 'Erro de conexão',
|
|
195
|
+
'aborted': 'Gravação cancelada',
|
|
196
|
+
'language-not-supported': 'Idioma não suportado',
|
|
197
|
+
'service-not-allowed': 'Serviço não permitido',
|
|
198
|
+
};
|
|
199
|
+
return messages[error] || `Erro: ${error}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// =============================================================================
|
|
203
|
+
// ArchbaseSpeechToTextButton Component
|
|
204
|
+
// =============================================================================
|
|
205
|
+
|
|
206
|
+
export interface ArchbaseSpeechToTextButtonProps {
|
|
207
|
+
/** Callback ao obter transcrição */
|
|
208
|
+
onTranscript: (transcript: string) => void;
|
|
209
|
+
/** Idioma (padrão: pt-BR) */
|
|
210
|
+
lang?: string;
|
|
211
|
+
/** Modo contínuo */
|
|
212
|
+
continuous?: boolean;
|
|
213
|
+
/** Desabilitado */
|
|
214
|
+
disabled?: boolean;
|
|
215
|
+
/** Tamanho do botão */
|
|
216
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
217
|
+
/** Cor */
|
|
218
|
+
color?: string;
|
|
219
|
+
/** Tooltip quando desabilitado/não suportado */
|
|
220
|
+
unsupportedTooltip?: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function ArchbaseSpeechToTextButton({
|
|
224
|
+
onTranscript,
|
|
225
|
+
lang = 'pt-BR',
|
|
226
|
+
continuous = false,
|
|
227
|
+
disabled = false,
|
|
228
|
+
size = 'md',
|
|
229
|
+
color = 'blue',
|
|
230
|
+
unsupportedTooltip = 'Reconhecimento de voz não suportado neste navegador',
|
|
231
|
+
}: ArchbaseSpeechToTextButtonProps) {
|
|
232
|
+
const {
|
|
233
|
+
isListening,
|
|
234
|
+
isSupported,
|
|
235
|
+
error,
|
|
236
|
+
start,
|
|
237
|
+
stop,
|
|
238
|
+
} = useArchbaseSpeechToText({
|
|
239
|
+
lang,
|
|
240
|
+
continuous,
|
|
241
|
+
onTranscript: (text, isFinal) => {
|
|
242
|
+
if (isFinal) {
|
|
243
|
+
onTranscript(text);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const handleClick = useCallback(() => {
|
|
249
|
+
if (isListening) {
|
|
250
|
+
stop();
|
|
251
|
+
} else {
|
|
252
|
+
start();
|
|
253
|
+
}
|
|
254
|
+
}, [isListening, start, stop]);
|
|
255
|
+
|
|
256
|
+
if (!isSupported) {
|
|
257
|
+
return (
|
|
258
|
+
<Tooltip label={unsupportedTooltip}>
|
|
259
|
+
<ActionIcon
|
|
260
|
+
variant="light"
|
|
261
|
+
color="gray"
|
|
262
|
+
size={size}
|
|
263
|
+
disabled
|
|
264
|
+
>
|
|
265
|
+
<IconMicrophoneOff size={16} />
|
|
266
|
+
</ActionIcon>
|
|
267
|
+
</Tooltip>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<Tooltip label={isListening ? 'Parar gravação' : 'Gravar voz'}>
|
|
273
|
+
<ActionIcon
|
|
274
|
+
variant={isListening ? 'filled' : 'light'}
|
|
275
|
+
color={isListening ? 'red' : color}
|
|
276
|
+
size={size}
|
|
277
|
+
disabled={disabled}
|
|
278
|
+
onClick={handleClick}
|
|
279
|
+
style={{
|
|
280
|
+
animation: isListening ? 'pulse 1.5s infinite' : undefined,
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
{isListening ? <IconPlayerStop size={16} /> : <IconMicrophone size={16} />}
|
|
284
|
+
</ActionIcon>
|
|
285
|
+
</Tooltip>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// =============================================================================
|
|
290
|
+
// ArchbaseSpeechToTextInput Component
|
|
291
|
+
// =============================================================================
|
|
292
|
+
|
|
293
|
+
export interface ArchbaseSpeechToTextInputProps extends Omit<TextInputProps, 'value' | 'onChange'> {
|
|
294
|
+
/** Valor atual */
|
|
295
|
+
value?: string;
|
|
296
|
+
/** Callback ao mudar */
|
|
297
|
+
onChange?: (value: string) => void;
|
|
298
|
+
/** Idioma (padrão: pt-BR) */
|
|
299
|
+
lang?: string;
|
|
300
|
+
/** Modo contínuo */
|
|
301
|
+
continuous?: boolean;
|
|
302
|
+
/** Substituir ou anexar transcrição */
|
|
303
|
+
mode?: 'replace' | 'append';
|
|
304
|
+
/** Mostrar indicador de gravação */
|
|
305
|
+
showRecordingIndicator?: boolean;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function ArchbaseSpeechToTextInput({
|
|
309
|
+
value = '',
|
|
310
|
+
onChange,
|
|
311
|
+
lang = 'pt-BR',
|
|
312
|
+
continuous = false,
|
|
313
|
+
mode = 'append',
|
|
314
|
+
showRecordingIndicator = true,
|
|
315
|
+
...props
|
|
316
|
+
}: ArchbaseSpeechToTextInputProps) {
|
|
317
|
+
const handleTranscript = useCallback(
|
|
318
|
+
(transcript: string) => {
|
|
319
|
+
if (mode === 'replace') {
|
|
320
|
+
onChange?.(transcript);
|
|
321
|
+
} else {
|
|
322
|
+
onChange?.(value ? `${value} ${transcript}` : transcript);
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
[onChange, value, mode]
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const {
|
|
329
|
+
isListening,
|
|
330
|
+
isSupported,
|
|
331
|
+
} = useArchbaseSpeechToText({ lang, continuous });
|
|
332
|
+
|
|
333
|
+
return (
|
|
334
|
+
<TextInput
|
|
335
|
+
{...props}
|
|
336
|
+
value={value}
|
|
337
|
+
onChange={(e) => onChange?.(e.target.value)}
|
|
338
|
+
rightSection={
|
|
339
|
+
<Box style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
|
340
|
+
{showRecordingIndicator && isListening && (
|
|
341
|
+
<Box
|
|
342
|
+
style={{
|
|
343
|
+
width: 8,
|
|
344
|
+
height: 8,
|
|
345
|
+
borderRadius: '50%',
|
|
346
|
+
backgroundColor: 'var(--mantine-color-red-6)',
|
|
347
|
+
animation: 'pulse 1s infinite',
|
|
348
|
+
}}
|
|
349
|
+
/>
|
|
350
|
+
)}
|
|
351
|
+
<ArchbaseSpeechToTextButton
|
|
352
|
+
onTranscript={handleTranscript}
|
|
353
|
+
lang={lang}
|
|
354
|
+
continuous={continuous}
|
|
355
|
+
size="xs"
|
|
356
|
+
/>
|
|
357
|
+
</Box>
|
|
358
|
+
}
|
|
359
|
+
rightSectionWidth={isListening ? 52 : 36}
|
|
360
|
+
/>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// =============================================================================
|
|
365
|
+
// ArchbaseSpeechToTextArea Component
|
|
366
|
+
// =============================================================================
|
|
367
|
+
|
|
368
|
+
export interface ArchbaseSpeechToTextAreaProps extends Omit<TextareaProps, 'value' | 'onChange'> {
|
|
369
|
+
/** Valor atual */
|
|
370
|
+
value?: string;
|
|
371
|
+
/** Callback ao mudar */
|
|
372
|
+
onChange?: (value: string) => void;
|
|
373
|
+
/** Idioma (padrão: pt-BR) */
|
|
374
|
+
lang?: string;
|
|
375
|
+
/** Modo contínuo */
|
|
376
|
+
continuous?: boolean;
|
|
377
|
+
/** Substituir ou anexar transcrição */
|
|
378
|
+
mode?: 'replace' | 'append';
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function ArchbaseSpeechToTextArea({
|
|
382
|
+
value = '',
|
|
383
|
+
onChange,
|
|
384
|
+
lang = 'pt-BR',
|
|
385
|
+
continuous = true,
|
|
386
|
+
mode = 'append',
|
|
387
|
+
...props
|
|
388
|
+
}: ArchbaseSpeechToTextAreaProps) {
|
|
389
|
+
const handleTranscript = useCallback(
|
|
390
|
+
(transcript: string) => {
|
|
391
|
+
if (mode === 'replace') {
|
|
392
|
+
onChange?.(transcript);
|
|
393
|
+
} else {
|
|
394
|
+
onChange?.(value ? `${value} ${transcript}` : transcript);
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
[onChange, value, mode]
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
return (
|
|
401
|
+
<Box style={{ position: 'relative' }}>
|
|
402
|
+
<Textarea
|
|
403
|
+
{...props}
|
|
404
|
+
value={value}
|
|
405
|
+
onChange={(e) => onChange?.(e.target.value)}
|
|
406
|
+
/>
|
|
407
|
+
<Box
|
|
408
|
+
style={{
|
|
409
|
+
position: 'absolute',
|
|
410
|
+
right: 8,
|
|
411
|
+
bottom: 8,
|
|
412
|
+
}}
|
|
413
|
+
>
|
|
414
|
+
<ArchbaseSpeechToTextButton
|
|
415
|
+
onTranscript={handleTranscript}
|
|
416
|
+
lang={lang}
|
|
417
|
+
continuous={continuous}
|
|
418
|
+
size="sm"
|
|
419
|
+
/>
|
|
420
|
+
</Box>
|
|
421
|
+
</Box>
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// =============================================================================
|
|
426
|
+
// CSS Keyframes (inject via style tag)
|
|
427
|
+
// =============================================================================
|
|
428
|
+
|
|
429
|
+
const pulseKeyframes = `
|
|
430
|
+
@keyframes pulse {
|
|
431
|
+
0% { opacity: 1; transform: scale(1); }
|
|
432
|
+
50% { opacity: 0.7; transform: scale(1.1); }
|
|
433
|
+
100% { opacity: 1; transform: scale(1); }
|
|
434
|
+
}
|
|
435
|
+
`;
|
|
436
|
+
|
|
437
|
+
// Inject keyframes
|
|
438
|
+
if (typeof document !== 'undefined') {
|
|
439
|
+
const style = document.createElement('style');
|
|
440
|
+
style.textContent = pulseKeyframes;
|
|
441
|
+
document.head.appendChild(style);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export default ArchbaseSpeechToTextInput;
|