@fluencypassdevs/cycle 1.9.7 → 1.13.0

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.
@@ -0,0 +1,142 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { MessageRatingValue, RatingLabel, MessageRatingLabels } from '../ui/message-rating.js';
4
+
5
+ type ChatThreadMessageStatus = "sent" | "pending" | "failed";
6
+ type ChatThreadPersona = "ai" | "user" | "system";
7
+ interface ChatThreadMessage {
8
+ id: string;
9
+ persona: ChatThreadPersona;
10
+ status?: ChatThreadMessageStatus;
11
+ text?: string;
12
+ audioSrc?: string;
13
+ audioPeaks?: number[];
14
+ /** Mensagem de erro pra exibir quando `persona="ai"` e `status="failed"` */
15
+ errorText?: string;
16
+ /**
17
+ * Quando true em uma mensagem da IA, renderiza o `MessageRating` (5 emojis) logo
18
+ * abaixo da bubble — alinhado com a IA, parte da mesma "linha visual" da mensagem.
19
+ * Apos o usuario responder, o rating some automaticamente (fade-out + slide-down).
20
+ *
21
+ * Usado quando a IA pede avaliacao da atividade: o consumer adiciona a msg da IA
22
+ * com este campo `true` no array `messages` e ouve `onRate` para receber a resposta.
23
+ */
24
+ requestRating?: boolean;
25
+ }
26
+ type ChatThreadState = "idle" | "sending" | "thinking" | "error";
27
+ interface QuotaExhaustedConfig {
28
+ title?: string;
29
+ description?: string;
30
+ ctaLabel?: string;
31
+ cancelLabel?: string;
32
+ onCta?: () => void;
33
+ onCancel?: () => void;
34
+ }
35
+ interface ChatThreadProps extends Omit<React.ComponentProps<"div">, "onChange"> {
36
+ /** Lista de mensagens da conversa */
37
+ messages: ChatThreadMessage[];
38
+ /** Estado global da conversa (controlled) */
39
+ state?: ChatThreadState;
40
+ /** Quando true e thread vazio, monta direto em thinking (cenario Class — IA fala primeiro) */
41
+ initialThinking?: boolean;
42
+ onSendText?: (text: string) => void;
43
+ /** Disparado quando user confirma envio do audio gravado (MessageBar dispara apos release/lock).
44
+ * Consumer gerencia MediaRecorder e tem acesso ao Blob no momento que isso for chamado. */
45
+ onSendAudio?: () => void;
46
+ /** Retry de mensagem do usuario que falhou enviar (B2) */
47
+ onRetryMessage?: (messageId: string) => void;
48
+ /** Regenerar resposta da IA com erro (B3) */
49
+ onRegenerateResponse?: () => void;
50
+ /** Cancelar resposta da IA mid-thinking (F1). Passar este callback **ativa** o botao
51
+ * "Parar resposta" no rodape durante o estado `thinking`. Se omitido, o MessageBar
52
+ * some com animacao de saida quando a IA esta pensando e volta com animacao de entrada
53
+ * quando termina — o consumer indica que nao quer expor cancelamento. */
54
+ onStopResponse?: () => void;
55
+ /** Carregar mensagens antigas (G1 — scroll infinito) */
56
+ onLoadMore?: () => Promise<void> | void;
57
+ /** Dispara quando o user pressiona o mic. Consumer chama getUserMedia + MediaRecorder. */
58
+ onStartRecording?: () => void;
59
+ /** Dispara quando o user pausa a gravacao. Consumer faz recorder.stop() + cria Blob. */
60
+ onPauseRecording?: () => void;
61
+ /** Dispara quando o user retoma gravacao apos pause. */
62
+ onResumeRecording?: () => void;
63
+ /** Dispara quando o user cancela a gravacao. Consumer cleanup do MediaRecorder. */
64
+ onCancelRecording?: () => void;
65
+ /** Toggle play/pause do audio gravado durante o estado `paused` do MessageBar. */
66
+ onTogglePlay?: () => void;
67
+ /** Callback de seek no waveform do audio gravado (durante paused). */
68
+ onSeekPlayback?: (progress: number) => void;
69
+ /** Stream do microfone durante recording — usado pelo MessageBar pra renderizar o live waveform. */
70
+ recordingStream?: MediaStream | null;
71
+ /** Duracao da gravacao em segundos (controlado pelo consumer via setInterval). */
72
+ recordingDuration?: number;
73
+ /** Indica se o audio gravado esta tocando (durante paused). */
74
+ isPlaying?: boolean;
75
+ /** Progresso de playback (0-1) — usado pra sincronizar dot verde no waveform. */
76
+ playbackProgress?: number;
77
+ /** Mostra banner de offline + disabled MessageBar (C1) */
78
+ offline?: boolean;
79
+ /** Timestamp epoch ate quando bloquear envio (C2). null/undefined = sem rate limit */
80
+ rateLimitedUntil?: number | null;
81
+ /** Texto do banner de rate limit. Default: "Aguarde {s}s antes de enviar nova mensagem" */
82
+ rateLimitBannerText?: (secondsRemaining: number) => string;
83
+ /** Modal de cota esgotada (C3) */
84
+ quotaExhausted?: boolean;
85
+ quotaExhaustedConfig?: QuotaExhaustedConfig;
86
+ /**
87
+ * Callback disparado quando o usuario responde um rating de uma mensagem com `requestRating=true`.
88
+ * Recebe:
89
+ * - `messageId`: id da mensagem da IA que pediu avaliacao
90
+ * - `value`: numero 1-5
91
+ * - `label`: objeto com emoji/title/subtitle correspondente ao value
92
+ *
93
+ * O consumer tipicamente usa esses dados para adicionar uma nova mensagem do usuario no array
94
+ * `messages` com o texto da escolha (ex: `label.subtitle` em PT-BR). O `MessageRating` some
95
+ * imediatamente apos o clique (sem estado "selecionado" visual).
96
+ */
97
+ onRate?: (messageId: string, value: MessageRatingValue, label: RatingLabel) => void;
98
+ /**
99
+ * Labels customizadas do `MessageRating` (sobrescreve PT-BR defaults).
100
+ * Passado pro componente E usado no callback `onRate` ao montar o `label`.
101
+ */
102
+ ratingLabels?: Partial<MessageRatingLabels>;
103
+ placeholder?: string;
104
+ maxLength?: number;
105
+ /** Modo so audio — passa pro MessageBar como state base */
106
+ audioOnlyMode?: boolean;
107
+ /**
108
+ * Limite de duracao da gravacao em segundos (configurado pelo consumer).
109
+ * Quando atingido, o ChatThread auto-pausa a gravacao (vai pro paused state com
110
+ * preview play/cancel/send) — a menos que `onMaxDurationReached` seja passado,
111
+ * caso em que o consumer assume controle. Sem essa prop, sem limite.
112
+ */
113
+ maxRecordingDuration?: number;
114
+ /** Quantos segundos antes do limite ativar o warning visual (timer destructive
115
+ * + label "Xs restantes"). Default 10. Ignorado sem `maxRecordingDuration`. */
116
+ warnAtSecondsLeft?: number;
117
+ /** Label do warning. Default pt-BR: `(s) => \`${s}s restantes\``. */
118
+ secondsLeftLabel?: (secondsLeft: number) => string;
119
+ /**
120
+ * Callback opcional disparado ao atingir o limite. Se omitido, ChatThread
121
+ * auto-pausa internamente. Se passado, **substitui** o auto-pause — o consumer
122
+ * decide o que fazer (ex: mostrar toast antes de pausar manualmente).
123
+ */
124
+ onMaxDurationReached?: () => void;
125
+ /** URL da imagem do avatar do usuario (aparece em todas as msgs do user no desktop). */
126
+ userAvatar?: string;
127
+ /** Nome do usuario (usado para iniciais no fallback do avatar e alt da imagem). */
128
+ userName?: string;
129
+ /** Default: "Sem conexao. Tentando reconectar..." */
130
+ offlineBannerText?: string;
131
+ /** Default: "Tentar novamente" */
132
+ retryButtonText?: string;
133
+ /** Default: "Regenerar resposta" */
134
+ regenerateButtonText?: string;
135
+ /** Default: "Parar resposta" */
136
+ stopResponseText?: string;
137
+ /** Default: "Desculpe, nao consegui responder." */
138
+ defaultAiErrorText?: string;
139
+ }
140
+ declare function ChatThread({ messages, state, initialThinking, onSendText, onSendAudio, onRetryMessage, onRegenerateResponse, onStopResponse, onLoadMore, onStartRecording, onPauseRecording, onResumeRecording, onCancelRecording, onTogglePlay, onSeekPlayback, recordingStream, recordingDuration, isPlaying, playbackProgress, offline, rateLimitedUntil, rateLimitBannerText, quotaExhausted, quotaExhaustedConfig, onRate, ratingLabels, placeholder, maxLength, audioOnlyMode, maxRecordingDuration, warnAtSecondsLeft, secondsLeftLabel, onMaxDurationReached, userAvatar, userName, offlineBannerText, retryButtonText, regenerateButtonText, stopResponseText, defaultAiErrorText, className, ...props }: ChatThreadProps): react_jsx_runtime.JSX.Element;
141
+
142
+ export { ChatThread, type ChatThreadMessage, type ChatThreadMessageStatus, type ChatThreadPersona, type ChatThreadProps, type ChatThreadState, type QuotaExhaustedConfig };
@@ -0,0 +1,15 @@
1
+ export { ChatThread } from '../chunk-JGUDRAWA.js';
2
+ import '../chunk-3EFI7PYC.js';
3
+ import '../chunk-CG7NXMBC.js';
4
+ import '../chunk-6OYSTCGP.js';
5
+ import '../chunk-CWMXYPWK.js';
6
+ import '../chunk-F2XA2Z75.js';
7
+ import '../chunk-JPEDYOV7.js';
8
+ import '../chunk-V7M2NHUO.js';
9
+ import '../chunk-MSLQRGSP.js';
10
+ import '../chunk-5I4PGGLN.js';
11
+ import '../chunk-JJETOZMI.js';
12
+ import '../chunk-TYCPXAXF.js';
13
+ import '../chunk-YINJ5YZ5.js';
14
+ //# sourceMappingURL=chat-thread.js.map
15
+ //# sourceMappingURL=chat-thread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-thread.js"}
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export { ChatBubble, ChatBubbleProps, chatBubbleVariants } from './ui/chat-bubbl
31
31
  export { ChatAudio, ChatAudioProps, ChatMessage, ChatMessageProps, chatMessageVariants } from './ui/chat-message.js';
32
32
  export { MessageRating, MessageRatingLabels, MessageRatingProps, MessageRatingValue, RatingLabel } from './ui/message-rating.js';
33
33
  export { MessageBar, MessageBarProps, MessageBarState } from './ui/message-bar.js';
34
+ export { ChatThread, ChatThreadMessage, ChatThreadMessageStatus, ChatThreadPersona, ChatThreadProps, ChatThreadState, QuotaExhaustedConfig } from './composites/chat-thread.js';
34
35
  export { ChatPanel, ChatMessage as ChatPanelMessage, ChatPanelProps } from './ui/chat-panel.js';
35
36
  export { LikeDislike, LikeDislikeProps, LikeDislikeValue, likeDislikeVariants } from './ui/like-dislike.js';
36
37
  export { LiveWaiting, LiveWaitingProps } from './ui/live-waiting.js';
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
+ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './chunk-NOMLQHZS.js';
1
2
  export { Editor } from './chunk-D4UH2HJQ.js';
2
3
  export { ClassLogo, GroupTalkLogo, PrivateTalkLogo, ProductLogo } from './chunk-66CU7J2I.js';
3
4
  export { FluencypassIcon, FluencypassLogo } from './chunk-5LZHXNBV.js';
5
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './chunk-IGMII4BK.js';
4
6
  export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './chunk-PY2BIZNB.js';
5
7
  export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from './chunk-F2Q3E2ZM.js';
6
8
  export { Skeleton } from './chunk-2EKU7RP4.js';
@@ -8,24 +10,23 @@ export { Spinner } from './chunk-5XNYJECW.js';
8
10
  export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './chunk-5NKTYXWQ.js';
9
11
  export { Fab, fabVariants } from './chunk-7NFHHOAE.js';
10
12
  export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from './chunk-YJ4U7ISM.js';
11
- export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './chunk-NOMLQHZS.js';
13
+ export { AudioPlayer } from './chunk-DCNZ2DRR.js';
12
14
  export { VideoPlayer } from './chunk-V3CBOIGK.js';
15
+ export { playerLocales } from './chunk-C6BQAAHX.js';
13
16
  export { Toaster, cycleToast } from './chunk-ELZCZ6ZH.js';
14
17
  export { Alert, AlertAction, AlertClose, AlertDescription, AlertTitle, alertVariants } from './chunk-7ZXAU2CD.js';
15
- export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from './chunk-3EFI7PYC.js';
16
18
  export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './chunk-SZUWVHP4.js';
17
19
  export { Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger } from './chunk-EF6FQT4Y.js';
18
- export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './chunk-IGMII4BK.js';
19
- export { ChatAudio, ChatMessage, chatMessageVariants } from './chunk-YMWRR7ET.js';
20
- export { MessageRating } from './chunk-37C2K2NM.js';
21
- export { MessageBar } from './chunk-27PO7X4G.js';
20
+ export { ChatThread } from './chunk-JGUDRAWA.js';
21
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from './chunk-3EFI7PYC.js';
22
+ export { ChatAudio, ChatMessage, chatMessageVariants } from './chunk-CG7NXMBC.js';
23
+ export { MessageRating } from './chunk-6OYSTCGP.js';
24
+ export { MessageBar } from './chunk-CWMXYPWK.js';
22
25
  export { ChatPanel } from './chunk-L32AMI4K.js';
23
26
  export { ChatBubble, chatBubbleVariants } from './chunk-HZJRM5EK.js';
24
27
  export { LikeDislike, likeDislikeVariants } from './chunk-F2XA2Z75.js';
25
- export { LiveWaiting } from './chunk-L2DJS6PG.js';
26
- export { AudioPlayer } from './chunk-DCNZ2DRR.js';
27
- export { playerLocales } from './chunk-C6BQAAHX.js';
28
28
  export { Achievement, Ai, Answer, Badge as BadgeIcon, Certificate, Chat as ChatIcon, Checkpoint, Completion, Conversation, Course, Deadline, Dialogue, Dictionary, Diploma, DotLive, Exercise, Feedback, Flashcard, Fluency, Goal, Grammar, GroupClass, Highlight, Language, Lesson, Listening, Live, MemoryCard, Milestone, Module, Presentation, PrivateClass, Progress as ProgressIcon, Question, Quiz, Ray, Reading, Recap, RecordedClass, Recurring, Repetition, Required, Schedule, Sentence, Streak, Task, Translate, Unit, Vocabulary, Whiteboard } from './chunk-JPEDYOV7.js';
29
+ export { LiveWaiting } from './chunk-L2DJS6PG.js';
29
30
  export { CycleIcon, ICON_SIZES } from './chunk-V7M2NHUO.js';
30
31
  export { ProgressStage } from './chunk-NYJMA2T7.js';
31
32
  export { ProgressDot, dotVariants, progressDotVariants } from './chunk-ZTANTDKS.js';
@@ -10,9 +10,14 @@ declare const chatMessageVariants: (props?: ({
10
10
  interface ChatMessageProps extends Omit<React.ComponentProps<"div">, "content">, VariantProps<typeof chatMessageVariants> {
11
11
  /** Quem enviou: AI (assistente), user (aluno), system (mensagem do sistema) */
12
12
  persona: "ai" | "user" | "system";
13
- /** Texto da mensagem (opcional se houver apenas audio) */
13
+ /** Texto da mensagem. Convencao do produto:
14
+ * - Em `persona="ai"` com `audioSrc`, o texto e o roteiro/legenda do audio TTS.
15
+ * - Em `persona="user"` com `audioSrc`, o texto e a transcricao do audio (gerada por IA).
16
+ * Em ambos os casos, aparece em bubble separada acima do audio. */
14
17
  text?: string;
15
- /** URL do audio — renderiza AudioPlayer dentro do bubble */
18
+ /** URL do audio — renderiza AudioPlayer dentro do bubble. Convencao do produto:
19
+ * toda msg da IA tem `text` + `audioSrc` (TTS) e toda msg do user com audio tem
20
+ * `text` (transcricao). Garante acessibilidade (leitura + escuta) e busca no historico. */
16
21
  audioSrc?: string;
17
22
  /** Avatar do user (so usado em persona="user") */
18
23
  avatar?: string;
@@ -1,4 +1,4 @@
1
- export { ChatAudio, ChatMessage, chatMessageVariants } from '../chunk-YMWRR7ET.js';
1
+ export { ChatAudio, ChatMessage, chatMessageVariants } from '../chunk-CG7NXMBC.js';
2
2
  import '../chunk-F2XA2Z75.js';
3
3
  import '../chunk-JPEDYOV7.js';
4
4
  import '../chunk-V7M2NHUO.js';
@@ -63,7 +63,30 @@ interface MessageBarProps extends Omit<React.ComponentProps<"div">, "onChange">
63
63
  onSeekPlayback?: (progress: number) => void;
64
64
  /** Placeholder do input */
65
65
  placeholder?: string;
66
+ /**
67
+ * Limite de duracao da gravacao em segundos. Quando omitido, sem limite
68
+ * (comportamento default). Quando atingido, o componente dispara
69
+ * `onMaxDurationReached` UMA VEZ — o ChatThread usa esse callback pra auto-pausar;
70
+ * consumers diretos do MessageBar podem usar pra customizar.
71
+ */
72
+ maxRecordingDuration?: number;
73
+ /**
74
+ * Quantos segundos antes do limite ativar o warning visual
75
+ * (timer em vermelho + label "Xs restantes" abaixo). Default: 10.
76
+ * Ignorado se `maxRecordingDuration` nao for passado.
77
+ */
78
+ warnAtSecondsLeft?: number;
79
+ /**
80
+ * Callback disparado uma unica vez quando `recordingDuration` >= `maxRecordingDuration`.
81
+ * Reseta automaticamente quando o componente sai do estado `recording`.
82
+ */
83
+ onMaxDurationReached?: () => void;
84
+ /**
85
+ * Label do warning inline. Recebe quantos segundos restam, retorna string.
86
+ * Default pt-BR: `(s) => \`${s}s restantes\``.
87
+ */
88
+ secondsLeftLabel?: (secondsLeft: number) => string;
66
89
  }
67
- declare function MessageBar({ state, value, onChange, onSendText, onStartRecording, onPauseRecording, onResumeRecording, onCancelRecording, onSendAudio, onTogglePlay, recordingDuration, isPlaying, recordingStream, playbackProgress, onSeekPlayback, placeholder, className, ...props }: MessageBarProps): react_jsx_runtime.JSX.Element;
90
+ declare function MessageBar({ state, value, onChange, onSendText, onStartRecording, onPauseRecording, onResumeRecording, onCancelRecording, onSendAudio, onTogglePlay, recordingDuration, isPlaying, recordingStream, playbackProgress, onSeekPlayback, placeholder, maxRecordingDuration, warnAtSecondsLeft, onMaxDurationReached, secondsLeftLabel, className, ...props }: MessageBarProps): react_jsx_runtime.JSX.Element;
68
91
 
69
92
  export { MessageBar, type MessageBarProps, type MessageBarState };
@@ -1,4 +1,4 @@
1
- export { MessageBar } from '../chunk-27PO7X4G.js';
1
+ export { MessageBar } from '../chunk-CWMXYPWK.js';
2
2
  import '../chunk-TYCPXAXF.js';
3
3
  import '../chunk-YINJ5YZ5.js';
4
4
  //# sourceMappingURL=message-bar.js.map
@@ -24,6 +24,7 @@ interface MessageRatingProps extends Omit<React.ComponentProps<"div">, "onChange
24
24
  /** Titulo opcional acima das opcoes */
25
25
  title?: string;
26
26
  }
27
+ declare const DEFAULT_MESSAGE_RATING_LABELS: MessageRatingLabels;
27
28
  declare function MessageRating({ value: controlledValue, defaultValue, onChange, layout, labels: labelOverrides, disabled, title, className, ...props }: MessageRatingProps): react_jsx_runtime.JSX.Element;
28
29
 
29
- export { MessageRating, type MessageRatingLabels, type MessageRatingProps, type MessageRatingValue, type RatingLabel };
30
+ export { DEFAULT_MESSAGE_RATING_LABELS, MessageRating, type MessageRatingLabels, type MessageRatingProps, type MessageRatingValue, type RatingLabel };
@@ -1,4 +1,4 @@
1
- export { MessageRating } from '../chunk-37C2K2NM.js';
1
+ export { DEFAULT_MESSAGE_RATING_LABELS, MessageRating } from '../chunk-6OYSTCGP.js';
2
2
  import '../chunk-TYCPXAXF.js';
3
3
  import '../chunk-YINJ5YZ5.js';
4
4
  //# sourceMappingURL=message-rating.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluencypassdevs/cycle",
3
- "version": "1.9.7",
3
+ "version": "1.13.0",
4
4
  "description": "Cycle Design System — UI component library by Fluencypass",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/ui/message-bar.tsx"],"names":["_a","_b"],"mappings":"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","file":"chunk-27PO7X4G.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Mic, Send, Trash2, Pause, Play, Lock, ChevronUp, ChevronLeft } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* ─── Types ───────────────────────────────────────────────────── */\n\n/**\n * Estados visuais do MessageBar:\n * - `default`: input texto + botao mic (estado inicial, sem texto digitado)\n * - `audio-only`: apenas botao mic centralizado (modo so audio)\n * - `active`: input texto com conteudo digitado + botao send\n * - `disabled`: input desabilitado\n * - `recording`: barra de gravacao (timer + waveform live + delete/pause/send)\n * - `paused`: gravacao pausada (timer + waveform + play/delete/mic/send)\n */\nexport type MessageBarState =\n | \"default\"\n | \"audio-only\"\n | \"active\"\n | \"disabled\"\n | \"recording\"\n | \"paused\"\n\nexport interface MessageBarProps extends Omit<React.ComponentProps<\"div\">, \"onChange\"> {\n /** Estado visual do componente (controlado pelo consumer) */\n state?: MessageBarState\n /** Valor do input de texto */\n value?: string\n /** Callback ao digitar */\n onChange?: (value: string) => void\n /** Callback ao enviar texto (Enter ou clique no botao send) */\n onSendText?: (text: string) => void\n /** Inicia gravacao (consumer chama MediaRecorder.start) */\n onStartRecording?: () => void\n /** Pausa gravacao */\n onPauseRecording?: () => void\n /** Retoma gravacao */\n onResumeRecording?: () => void\n /** Cancela/deleta gravacao */\n onCancelRecording?: () => void\n /** Envia o audio gravado */\n onSendAudio?: () => void\n /** Toggle play/pause do audio gravado durante o estado `paused` */\n onTogglePlay?: () => void\n /** Duracao da gravacao em segundos (controlado pelo consumer) */\n recordingDuration?: number\n /** Indica se esta tocando o audio (durante state=paused) */\n isPlaying?: boolean\n /**\n * MediaStream do microfone (durante state=recording). Quando fornecido,\n * o componente analisa em tempo real e renderiza as barras conforme a voz.\n * Sem stream → fallback para waveform decorativo.\n *\n * Como usar:\n * ```ts\n * const stream = await navigator.mediaDevices.getUserMedia({ audio: true })\n * const recorder = new MediaRecorder(stream)\n * // Passa o MESMO stream pro MessageBar:\n * <MessageBar state=\"recording\" recordingStream={stream} ... />\n * ```\n */\n recordingStream?: MediaStream | null\n /**\n * Progresso do playback do audio gravado (0-1), usado durante state=paused.\n * Quando fornecido, o waveform mostra barras tocadas/nao tocadas + dot verde\n * sincronizado. Sem isso, o waveform mostra todas as barras como nao tocadas.\n */\n playbackProgress?: number\n /**\n * Callback ao clicar/arrastar no waveform durante state=paused.\n * Recebe o novo progresso (0-1); o consumer deve setar currentTime do audio.\n */\n onSeekPlayback?: (progress: number) => void\n /** Placeholder do input */\n placeholder?: string\n}\n\n/* ─── Helpers ─────────────────────────────────────────────────── */\n\nfunction formatDuration(seconds: number): string {\n if (!Number.isFinite(seconds) || seconds < 0) return \"00:00\"\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return `${m.toString().padStart(2, \"0\")}:${s.toString().padStart(2, \"0\")}`\n}\n\n/* ─── Sub-componentes ─────────────────────────────────────────── */\n\n/** Botao mic vermelho coral (theme-brand) — usado em default, audio-only e durante press.\n * - `variant=\"large\"` aumenta para 64x64 (overlay durante press)\n * - `pressed` aplica scale-110 + opacity 90\n * - Aceita pointer events para suportar press-and-hold (mobile WhatsApp-style) */\nfunction MicButton({\n onClick,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n size = \"default\",\n variant = \"default\",\n pressed = false,\n ariaLabel = \"Gravar audio\",\n className,\n style,\n}: {\n onClick?: () => void\n onPointerDown?: (e: React.PointerEvent<HTMLButtonElement>) => void\n onPointerMove?: (e: React.PointerEvent<HTMLButtonElement>) => void\n onPointerUp?: (e: React.PointerEvent<HTMLButtonElement>) => void\n onPointerCancel?: (e: React.PointerEvent<HTMLButtonElement>) => void\n size?: \"default\" | \"sm\"\n variant?: \"default\" | \"large\"\n pressed?: boolean\n ariaLabel?: string\n className?: string\n style?: React.CSSProperties\n}) {\n const buttonRef = React.useRef<HTMLButtonElement>(null)\n const hasPressFlow = !!onPointerDown\n\n /* touchstart non-passive — marca o gesto como NAO scroll desde o primeiro evento.\n * Critico pra Android Chrome (Blink): se o touchstart for passive (default no React),\n * o navegador classifica o gesto como \"potencialmente scroll\" e ignora preventDefault\n * posterior. Listener via addEventListener pra poder usar { passive: false }. */\n React.useEffect(() => {\n const btn = buttonRef.current\n if (!btn || !hasPressFlow) return\n const onTouchStart = (e: TouchEvent) => {\n e.preventDefault()\n }\n btn.addEventListener(\"touchstart\", onTouchStart, { passive: false })\n return () => btn.removeEventListener(\"touchstart\", onTouchStart)\n }, [hasPressFlow])\n\n const sizeClass =\n variant === \"large\" ? \"size-16\" : size === \"default\" ? \"size-10\" : \"size-8\"\n const radiusClass = variant === \"large\" ? \"rounded-lg\" : \"rounded-md\"\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={onClick}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerCancel}\n aria-pressed={pressed || undefined}\n className={cn(\n \"shrink-0 inline-flex items-center justify-center bg-primary text-primary-foreground theme-brand transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n sizeClass,\n radiusClass,\n pressed && \"opacity-90 select-none\",\n // touch-none aplicado sempre que ha press flow (nao so quando ja esta pressed),\n // pra Android Chrome nao classificar o touchstart como scroll\n (hasPressFlow || pressed) && \"touch-none\",\n className\n )}\n style={style}\n aria-label={ariaLabel}\n >\n <Mic className={variant === \"large\" ? \"size-6\" : \"size-5\"} />\n </button>\n )\n}\n\n/** Botao send verde (theme-positive) */\nfunction SendButton({\n onClick,\n disabled,\n ariaLabel = \"Enviar\",\n}: {\n onClick?: () => void\n disabled?: boolean\n ariaLabel?: string\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className=\"shrink-0 inline-flex items-center justify-center size-10 rounded-md bg-primary text-primary-foreground theme-positive transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label={ariaLabel}\n >\n <Send className=\"size-5\" fill=\"currentColor\" strokeWidth={0} />\n </button>\n )\n}\n\n/** Botao icon-only neutral (trash, pause, play, mic durante paused) */\nfunction IconButton({\n onClick,\n icon: Icon,\n ariaLabel,\n filled = false,\n}: {\n onClick?: () => void\n icon: React.ComponentType<{ className?: string; fill?: string; strokeWidth?: number }>\n ariaLabel: string\n filled?: boolean\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"shrink-0 inline-flex items-center justify-center size-10 rounded-md text-neutral-foreground hover:bg-muted/50 transition-colors focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n aria-label={ariaLabel}\n >\n <Icon\n className=\"size-5\"\n {...(filled ? { fill: \"currentColor\", strokeWidth: 0 } : {})}\n />\n </button>\n )\n}\n\n/** Indicador de gravacao (red dot pulsando) */\nfunction RecordingIndicator() {\n return (\n <span className=\"shrink-0 relative inline-flex items-center justify-center size-3\" aria-label=\"Gravando\">\n <span className=\"absolute inset-0 rounded-full bg-primary theme-brand animate-ping opacity-75\" />\n <span className=\"relative size-2.5 rounded-full bg-primary theme-brand\" />\n </span>\n )\n}\n\n/** Helper: agrega N samples brutos em K barras (pico por chunk). Quando samples.length\n * < barCount, \"estica\" via lookup proporcional (cada barra pega o sample mais proximo). */\nfunction aggregateSamples(samples: number[], barCount: number): number[] {\n if (samples.length === 0 || barCount === 0) return new Array(barCount).fill(0)\n const result = new Array(barCount).fill(0)\n // Poucos samples: estica via lookup proporcional\n if (samples.length < barCount) {\n for (let i = 0; i < barCount; i++) {\n const idx = Math.floor((i / barCount) * samples.length)\n result[i] = samples[idx] ?? 0\n }\n return result\n }\n // Muitos samples: agrega pegando o pico (max) do chunk\n const chunkSize = samples.length / barCount\n for (let i = 0; i < barCount; i++) {\n const start = Math.floor(i * chunkSize)\n const end = Math.floor((i + 1) * chunkSize)\n let max = 0\n for (let j = start; j < end && j < samples.length; j++) {\n if (samples[j] > max) max = samples[j]\n }\n result[i] = max\n }\n return result\n}\n\n/** LiveWaveform — analise em tempo real do microfone via AnalyserNode.\n * Comportamento estilo WhatsApp:\n * - **Preenche toda a largura disponivel** (ResizeObserver detecta width e calcula limite max de barras)\n * - Cada bar = 2px wide, 2px gap (4px stride)\n * - **Comeca VAZIO**: primeiras barras entram pela DIREITA e empurram pra esquerda\n * - Depois que enche: rolling window (mais antiga sai esquerda, nova entra direita)\n * - Visualmente: container alinha barras com `justify-end` */\nfunction LiveWaveform({\n stream,\n samplesRef,\n}: {\n stream?: MediaStream | null\n /** Ref opcional: quando fornecido, acumula TODOS os samples brutos da gravacao (para usar no\n * state=paused via RecordedWaveform). O LiveWaveform mantem seu rolling window separado. */\n samplesRef?: React.MutableRefObject<number[]>\n}) {\n const STRIDE = 4 // 2px barra + 2px gap\n const MIN_BARS = 20\n const containerRef = React.useRef<HTMLDivElement>(null)\n const [bars, setBars] = React.useState<number[]>([])\n const barCountRef = React.useRef<number>(MIN_BARS)\n\n /* ResizeObserver: ajusta o LIMITE de barras (nao o buffer atual, exceto se shrink). */\n React.useEffect(() => {\n const el = containerRef.current\n if (!el) return\n\n const updateBarCount = (width: number) => {\n const count = Math.max(MIN_BARS, Math.floor(width / STRIDE))\n barCountRef.current = count\n // Se o buffer atual passou do novo limite (shrink), trunca mantendo as mais recentes\n setBars((prev) => (prev.length > count ? prev.slice(prev.length - count) : prev))\n }\n\n updateBarCount(el.clientWidth)\n\n const ro = new ResizeObserver((entries) => {\n const width = entries[0]?.contentRect.width ?? 0\n updateBarCount(width)\n })\n ro.observe(el)\n\n return () => ro.disconnect()\n }, [])\n\n /* Audio analysis setup (so depende do stream) */\n React.useEffect(() => {\n if (!stream) {\n setBars([])\n return\n }\n\n const AudioContextClass =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext\n const audioContext = new AudioContextClass()\n const source = audioContext.createMediaStreamSource(stream)\n const analyser = audioContext.createAnalyser()\n analyser.fftSize = 256\n source.connect(analyser)\n\n const dataArray = new Uint8Array(analyser.frequencyBinCount)\n let rafId: number | null = null\n let lastUpdate = 0\n let cancelled = false\n\n const tick = (timestamp: number) => {\n if (cancelled) return\n // Throttle ~30fps (33ms entre samples)\n if (timestamp - lastUpdate >= 33) {\n lastUpdate = timestamp\n analyser.getByteTimeDomainData(dataArray)\n\n // RMS — amplitude media percebida\n let sum = 0\n for (let i = 0; i < dataArray.length; i++) {\n const v = (dataArray[i] - 128) / 128\n sum += v * v\n }\n const rms = Math.sqrt(sum / dataArray.length)\n\n // Acumula no ref do parent (para reaproveitar no state=paused via RecordedWaveform)\n if (samplesRef) samplesRef.current.push(rms)\n\n setBars((prev) => {\n // Enquanto nao encheu: append no final (vai aparecer na direita por causa do justify-end)\n if (prev.length < barCountRef.current) return [...prev, rms]\n // Cheio: rolling window (descarta mais antiga, adiciona nova)\n return [...prev.slice(1), rms]\n })\n }\n rafId = requestAnimationFrame(tick)\n }\n\n rafId = requestAnimationFrame(tick)\n\n return () => {\n cancelled = true\n if (rafId !== null) cancelAnimationFrame(rafId)\n void audioContext.close()\n }\n }, [stream, samplesRef])\n\n return (\n <div\n ref={containerRef}\n className=\"flex-1 relative h-8 min-w-0 overflow-hidden\"\n >\n <div className=\"absolute inset-y-0 left-0 right-0 flex items-center justify-end gap-[2px]\">\n {bars.map((amp, i) => {\n // Voz humana tende a ter RMS baixo (~0.05-0.3). Boost x4 para visual.\n const normalized = Math.min(amp * 4, 1)\n const height = Math.max(2, Math.round(normalized * 32))\n return (\n <div\n key={i}\n className=\"w-[2px] shrink-0 rounded-full bg-neutral-foreground\"\n style={{ height: `${height}px` }}\n />\n )\n })}\n </div>\n </div>\n )\n}\n\n/** RecordedWaveform — waveform real do audio ja gravado (usado no state=paused).\n * - Recebe samples brutos acumulados durante o recording (via samplesRef)\n * - Agrega em N barras via ResizeObserver (largura dinamica, igual ChatAudio)\n * - Barras tocadas (i / N <= progress) em `bg-neutral-foreground`, demais em `bg-neutral-ring`\n * - Dot verde sincronizado com o progresso\n * - Click/drag-to-seek via pointer events */\nfunction RecordedWaveform({\n samples,\n progress = 0,\n onSeek,\n}: {\n samples: number[]\n progress?: number\n onSeek?: (progress: number) => void\n}) {\n const STRIDE = 4 // 2px barra + 2px gap\n const MIN_BARS = 20\n const containerRef = React.useRef<HTMLDivElement>(null)\n const [barCount, setBarCount] = React.useState<number>(MIN_BARS)\n\n React.useEffect(() => {\n const el = containerRef.current\n if (!el) return\n const updateBarCount = (width: number) => {\n const count = Math.max(MIN_BARS, Math.floor(width / STRIDE))\n setBarCount(count)\n }\n updateBarCount(el.clientWidth)\n const ro = new ResizeObserver((entries) => {\n updateBarCount(entries[0]?.contentRect.width ?? 0)\n })\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n // Agrega samples acumulados em barCount barras + normaliza para 0-1 (relativo ao pico)\n const bars = React.useMemo(() => {\n const aggregated = aggregateSamples(samples, barCount)\n const maxPeak = Math.max(...aggregated, 0.01)\n return aggregated.map((p) => p / maxPeak)\n }, [samples, barCount])\n\n const isDraggingRef = React.useRef(false)\n\n const seekFromClientX = React.useCallback(\n (clientX: number) => {\n const el = containerRef.current\n if (!el || !onSeek) return\n const rect = el.getBoundingClientRect()\n const x = clientX - rect.left\n const newProgress = Math.max(0, Math.min(x / rect.width, 1))\n onSeek(newProgress)\n },\n [onSeek]\n )\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!onSeek) return\n isDraggingRef.current = true\n e.currentTarget.setPointerCapture(e.pointerId)\n seekFromClientX(e.clientX)\n }\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDraggingRef.current) return\n seekFromClientX(e.clientX)\n }\n const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDraggingRef.current) return\n isDraggingRef.current = false\n e.currentTarget.releasePointerCapture(e.pointerId)\n }\n\n // Largura natural do layout das barras (px), usada para posicionar o dot em pixels\n const barsLayoutWidth = bars.length * STRIDE - 2\n\n return (\n <div\n ref={containerRef}\n className={cn(\n \"flex-1 relative h-8 min-w-0 overflow-hidden select-none\",\n onSeek && \"touch-none cursor-pointer\"\n )}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n role={onSeek ? \"slider\" : undefined}\n aria-label={onSeek ? \"Posicao do audio\" : undefined}\n aria-valuemin={onSeek ? 0 : undefined}\n aria-valuemax={onSeek ? 100 : undefined}\n aria-valuenow={onSeek ? Math.round(progress * 100) : undefined}\n >\n <div className=\"absolute inset-y-0 left-0 flex items-center gap-[2px]\">\n {bars.map((amp, i) => {\n const isPlayed = i / bars.length <= progress\n const height = Math.max(2, Math.round(amp * 32))\n return (\n <div\n key={i}\n className={cn(\n \"w-[2px] shrink-0 rounded-full\",\n isPlayed ? \"bg-neutral-foreground\" : \"bg-neutral-ring\"\n )}\n style={{ height: `${height}px` }}\n />\n )\n })}\n </div>\n {progress > 0 && (\n <div\n className=\"absolute top-1/2 z-10 -translate-y-1/2 -translate-x-1/2 size-3 rounded-full bg-[#098A5E] shadow-md pointer-events-none\"\n style={{ left: `${progress * barsLayoutWidth}px` }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n )\n}\n\n/* ─── Press-to-record constants ───────────────────────────────── */\n\nconst LOCK_THRESHOLD = 120 // px arrastados pra cima → trava em modo hands-free\nconst CANCEL_THRESHOLD_RATIO = 0.65 // % da largura do MessageBar\nconst CANCEL_THRESHOLD_MIN = 140 // floor (telas pequenas — iPhone SE)\nconst CANCEL_THRESHOLD_MAX = 220 // ceiling (telas grandes — nao precisa atravessar a tela toda)\nconst MIN_DURATION = 1000 // ms — release antes disso cancela\n\n/** Calcula o threshold de cancel baseado na largura do container do MessageBar.\n * Sempre proporcional, com clamps min/max pra funcionar bem em telas pequenas (iPhone SE)\n * sem ficar trivialmente facil em telas grandes. */\nfunction computeCancelThreshold(containerWidth: number): number {\n return Math.min(\n CANCEL_THRESHOLD_MAX,\n Math.max(CANCEL_THRESHOLD_MIN, containerWidth * CANCEL_THRESHOLD_RATIO)\n )\n}\n\n/** PressedRecordingOverlay — UI exibida enquanto o usuario mantem o mic pressionado.\n * Inspirado no comportamento de gravacao de audio do WhatsApp.\n *\n * - Pill esquerda: live dot + timer + \"Deslize para cancelar\"\n * - Mic vermelho 64×64 (acompanha o cursor via translate clamped)\n * - Pill flutuante ACIMA do mic com lock + chevron up (indica \"deslize pra travar\")\n *\n * Variants:\n * - `default`: layout horizontal (cancel pill esquerda + mic direita)\n * - `audio-only`: layout horizontal centralizado (cancel pill curta + mic + timer pill) */\nfunction PressedRecordingOverlay({\n variant,\n duration,\n deltaX,\n deltaY,\n lockThreshold,\n cancelThreshold,\n}: {\n variant: \"default\" | \"audio-only\"\n duration: number\n deltaX: number\n deltaY: number\n lockThreshold: number\n cancelThreshold: number\n}) {\n const aboutToLock = deltaY <= -lockThreshold\n const aboutToCancel = deltaX <= -cancelThreshold\n // Clamp: so move pra cima/esquerda (delta negativo); ignora positivos\n const clampedX = Math.min(0, deltaX)\n const clampedY = Math.min(0, deltaY)\n // Restringe a UM EIXO POR VEZ — sem movimento diagonal.\n // Detecta direcao dominante (maior magnitude) e zera o outro eixo.\n const absX = Math.abs(clampedX)\n const absY = Math.abs(clampedY)\n const micTranslateX = absX >= absY ? clampedX : 0\n const micTranslateY = absY > absX ? clampedY : 0\n\n return (\n <div\n data-slot=\"message-bar\"\n data-state=\"recording-pressed\"\n className={cn(\n \"flex items-center gap-2 p-2 sm:gap-3 sm:p-0 touch-none select-none\",\n variant === \"audio-only\" && \"justify-center\"\n )}\n >\n {/* Layout: cancel-pill + mic (default) | cancel-pill + mic + timer-pill (audio-only) */}\n {variant === \"audio-only\" ? (\n <div className=\"relative flex items-center gap-2\">\n {/* Cancel pill (compact) */}\n <div\n className={cn(\n \"flex items-center gap-1 rounded-full bg-muted h-7 px-3 transition-colors\",\n aboutToCancel && \"bg-destructive/10\"\n )}\n >\n <ChevronLeft className=\"size-3 text-muted-foreground\" />\n <span\n className={cn(\n \"text-xs\",\n aboutToCancel ? \"text-destructive font-medium\" : \"text-muted-foreground\"\n )}\n >\n Cancelar\n </span>\n </div>\n\n {/* Mic + lock pill (anchor) */}\n <div className=\"relative\">\n {/* Lock pill ACIMA do mic */}\n <div\n className={cn(\n \"absolute left-1/2 -translate-x-1/2 bottom-full mb-2 flex flex-col items-center gap-3 rounded-t-full bg-muted h-20 w-8 py-3 transition-transform\",\n aboutToLock && \"scale-125 ring-2 ring-[#0EA460]\"\n )}\n aria-hidden=\"true\"\n >\n <Lock className={cn(\"size-3\", aboutToLock ? \"text-[#0EA460]\" : \"text-muted-foreground\")} />\n <ChevronUp className=\"size-3 text-muted-foreground animate-bounce\" />\n </div>\n\n <MicButton\n variant=\"large\"\n pressed\n ariaLabel=\"Gravando — arraste para cima para travar, para esquerda para cancelar\"\n className={cn(aboutToCancel && \"animate-shake\")}\n style={\n aboutToCancel\n ? undefined\n : { transform: `translate(${micTranslateX}px, ${micTranslateY}px) scale(1.1)` }\n }\n />\n </div>\n\n {/* Timer pill */}\n <div className=\"flex items-center gap-1 rounded-full bg-muted h-7 px-3\">\n <RecordingIndicator />\n <span className=\"text-sm tabular-nums text-neutral-foreground\">\n {formatDuration(duration)}\n </span>\n </div>\n </div>\n ) : (\n // Variant default: cancel pill flex-1 + mic\n <>\n <div\n className={cn(\n \"flex-1 flex items-center justify-between gap-2 rounded-xl bg-muted px-4 py-3 h-14\",\n aboutToCancel && \"bg-destructive/10\"\n )}\n >\n <div className=\"flex items-center gap-2\">\n <RecordingIndicator />\n <span className=\"text-sm tabular-nums text-neutral-foreground\">\n {formatDuration(duration)}\n </span>\n </div>\n <div\n className={cn(\n \"flex items-center gap-1 text-xs\",\n aboutToCancel ? \"text-destructive font-medium\" : \"text-muted-foreground\"\n )}\n >\n <ChevronLeft className=\"size-3\" />\n <span>Deslize para cancelar</span>\n </div>\n </div>\n\n {/* Mic + lock pill */}\n <div className=\"relative\">\n <div\n className={cn(\n \"absolute left-1/2 -translate-x-1/2 bottom-full mb-2 flex flex-col items-center gap-3 rounded-t-full bg-muted h-20 w-8 py-3 transition-transform\",\n aboutToLock && \"scale-125 ring-2 ring-[#0EA460]\"\n )}\n aria-hidden=\"true\"\n >\n <Lock className={cn(\"size-3\", aboutToLock ? \"text-[#0EA460]\" : \"text-muted-foreground\")} />\n <ChevronUp className=\"size-3 text-muted-foreground animate-bounce\" />\n </div>\n\n <MicButton\n variant=\"large\"\n pressed\n ariaLabel=\"Gravando — arraste para cima para travar, para esquerda para cancelar\"\n className={cn(aboutToCancel && \"animate-shake\")}\n style={\n aboutToCancel\n ? undefined\n : { transform: `translate(${micTranslateX}px, ${micTranslateY}px) scale(1.1)` }\n }\n />\n </div>\n </>\n )}\n </div>\n )\n}\n\n/* ─── Component principal ─────────────────────────────────────── */\n\nfunction MessageBar({\n state = \"default\",\n value = \"\",\n onChange,\n onSendText,\n onStartRecording,\n onPauseRecording,\n onResumeRecording,\n onCancelRecording,\n onSendAudio,\n onTogglePlay,\n recordingDuration = 0,\n isPlaying = false,\n recordingStream,\n playbackProgress = 0,\n onSeekPlayback,\n placeholder = \"Digite sua mensagem...\",\n className,\n ...props\n}: MessageBarProps) {\n // Acumula samples brutos do microfone durante recording — reaproveitado em paused via RecordedWaveform\n const samplesRef = React.useRef<number[]>([])\n\n // Reset dos samples quando inicia nova gravacao (transicao para recording a partir de outros estados)\n // Nao zera ao voltar de paused → recording (continua a mesma gravacao)\n const prevStateRef = React.useRef<MessageBarState>(state)\n // Lembra o ultimo base state (default/audio-only) pra escolher variant do overlay pressed\n const lastBaseStateRef = React.useRef<\"default\" | \"audio-only\">(\n state === \"audio-only\" ? \"audio-only\" : \"default\"\n )\n React.useEffect(() => {\n const prev = prevStateRef.current\n if (state === \"recording\" && prev !== \"paused\" && prev !== \"recording\") {\n samplesRef.current = []\n }\n if (state === \"default\" || state === \"audio-only\") {\n lastBaseStateRef.current = state\n }\n prevStateRef.current = state\n }, [state])\n\n /* ─── Press-to-record (WhatsApp-like, touch-only) ───────────── */\n const [isPressed, setIsPressed] = React.useState(false)\n const [pressDelta, setPressDelta] = React.useState({ x: 0, y: 0 })\n // Cancel threshold dinamico — calculado baseado na largura do container no pointerdown\n const [pressCancelThreshold, setPressCancelThreshold] = React.useState(CANCEL_THRESHOLD_MAX)\n const pressDeltaRef = React.useRef({ x: 0, y: 0 })\n const pressCancelThresholdRef = React.useRef(CANCEL_THRESHOLD_MAX)\n const pressInfoRef = React.useRef({ startX: 0, startY: 0, startTime: 0, locked: false })\n // Ref sincronizada com isPressed — usada por listener permanente de touchmove\n // (instalado no mount, mas so preventDefault quando esta pressionado)\n const isPressedRef = React.useRef(false)\n // Refs pros callbacks — handlers do window leem a versao mais recente sem precisar reinstalar listeners\n const callbacksRef = React.useRef({ onStartRecording, onCancelRecording, onSendAudio })\n React.useEffect(() => {\n callbacksRef.current = { onStartRecording, onCancelRecording, onSendAudio }\n })\n\n const updateDelta = (dx: number, dy: number) => {\n pressDeltaRef.current = { x: dx, y: dy }\n setPressDelta({ x: dx, y: dy })\n }\n\n /* Listener PERMANENTE de touchmove com preventDefault — instalado no mount.\n * Por que permanente: se instalar so quando isPressed=true (dentro do useEffect transient),\n * o iOS ja decidiu que o gesto e scroll/swipe ANTES do listener montar.\n * Solucao: listener sempre presente, com guard via isPressedRef.current. */\n React.useEffect(() => {\n const onTouchMove = (e: TouchEvent) => {\n if (isPressedRef.current) {\n e.preventDefault()\n }\n }\n window.addEventListener(\"touchmove\", onTouchMove, { passive: false })\n return () => window.removeEventListener(\"touchmove\", onTouchMove)\n }, [])\n\n const triggerHaptic = (ms = 50) => {\n if (typeof navigator !== \"undefined\" && typeof navigator.vibrate === \"function\") {\n try {\n navigator.vibrate(ms)\n } catch {\n /* ignore — alguns browsers podem rejeitar fora de user gesture */\n }\n }\n }\n\n // Listeners no window (sobrevivem a troca de DOM quando o overlay aparece e o MicButton original desmonta)\n // Sincroniza isPressedRef com isPressed pra o listener permanente de touchmove ler\n React.useEffect(() => {\n isPressedRef.current = isPressed\n }, [isPressed])\n\n // Listeners de pointer (transient): so existem durante o press flow\n React.useEffect(() => {\n if (!isPressed) return\n\n // touch-action: none em html + body bloqueia gestos nativos (backup, ja temos o\n // touchmove permanente com preventDefault)\n const prevHtmlTouchAction = document.documentElement.style.touchAction\n const prevBodyTouchAction = document.body.style.touchAction\n document.documentElement.style.touchAction = \"none\"\n document.body.style.touchAction = \"none\"\n\n const onMove = (e: PointerEvent) => {\n if (pressInfoRef.current.locked) return\n const { startX, startY } = pressInfoRef.current\n const dx = e.clientX - startX\n const dy = e.clientY - startY\n updateDelta(dx, dy)\n // Atinge lock threshold → trava em modo hands-free\n if (dy <= -LOCK_THRESHOLD) {\n pressInfoRef.current.locked = true\n triggerHaptic(50)\n setIsPressed(false)\n updateDelta(0, 0)\n }\n }\n\n const onEnd = () => {\n if (pressInfoRef.current.locked) return\n const { startTime } = pressInfoRef.current\n const elapsed = Date.now() - startTime\n const { x: dx } = pressDeltaRef.current\n\n setIsPressed(false)\n updateDelta(0, 0)\n\n if (dx <= -pressCancelThresholdRef.current || elapsed < MIN_DURATION) {\n triggerHaptic(50)\n callbacksRef.current.onCancelRecording?.()\n return\n }\n callbacksRef.current.onSendAudio?.()\n }\n\n window.addEventListener(\"pointermove\", onMove)\n window.addEventListener(\"pointerup\", onEnd)\n // pointercancel tratado como release (usa delta atual pra decidir cancel/send)\n window.addEventListener(\"pointercancel\", onEnd)\n return () => {\n window.removeEventListener(\"pointermove\", onMove)\n window.removeEventListener(\"pointerup\", onEnd)\n window.removeEventListener(\"pointercancel\", onEnd)\n document.documentElement.style.touchAction = prevHtmlTouchAction\n document.body.style.touchAction = prevBodyTouchAction\n }\n }, [isPressed])\n\n const handlePressStart = (e: React.PointerEvent<HTMLButtonElement>) => {\n // Desktop (mouse/pen): comportamento antigo de click — dispara onStartRecording, sai do flow press\n if (e.pointerType !== \"touch\") {\n onStartRecording?.()\n return\n }\n // Mede a largura do container do MessageBar pra calcular o cancel threshold adaptativo\n const wrapper = e.currentTarget.closest('[data-slot=\"message-bar\"]')\n const containerWidth =\n wrapper instanceof HTMLElement ? wrapper.clientWidth : window.innerWidth\n const threshold = computeCancelThreshold(containerWidth)\n pressCancelThresholdRef.current = threshold\n setPressCancelThreshold(threshold)\n\n pressInfoRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n startTime: Date.now(),\n locked: false,\n }\n updateDelta(0, 0)\n setIsPressed(true)\n onStartRecording?.()\n }\n\n const pressHandlers = {\n onPointerDown: handlePressStart,\n }\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey && value.trim()) {\n e.preventDefault()\n onSendText?.(value)\n }\n }\n\n /* ─── State: audio-only (so botao mic centralizado) ─────────── */\n if (state === \"audio-only\") {\n return (\n <div\n data-slot=\"message-bar\"\n data-state=\"audio-only\"\n className={cn(\"flex items-center justify-center p-2\", className)}\n {...props}\n >\n <MicButton {...pressHandlers} />\n </div>\n )\n }\n\n /* ─── State: recording + pressed (overlay WhatsApp-like) ────── */\n if (state === \"recording\" && isPressed) {\n return (\n <PressedRecordingOverlay\n variant={lastBaseStateRef.current}\n duration={recordingDuration}\n deltaX={pressDelta.x}\n deltaY={pressDelta.y}\n lockThreshold={LOCK_THRESHOLD}\n cancelThreshold={pressCancelThreshold}\n />\n )\n }\n\n /* ─── State: recording (hands-free, apos lock ou click no mic) ─ */\n if (state === \"recording\") {\n return (\n <div\n data-slot=\"message-bar\"\n data-state=\"recording\"\n className={cn(\n \"flex items-center gap-2 p-2 sm:gap-3 sm:p-0\",\n className\n )}\n {...props}\n >\n {/* Mobile: 2-row layout */}\n <div className=\"flex flex-col gap-2 w-full sm:contents\">\n {/* Top: trash + recording info + waveform (mobile) / inline (desktop) */}\n <div className=\"flex items-center gap-2 sm:contents\">\n {/* Trash — only inline at desktop, mobile shows in bottom row */}\n <div className=\"hidden sm:contents\">\n <IconButton\n onClick={onCancelRecording}\n icon={Trash2}\n ariaLabel=\"Cancelar gravacao\"\n />\n </div>\n\n {/* Recording bar — bg-muted container */}\n <div className=\"flex items-center gap-3 flex-1 rounded-2xl bg-muted px-4 py-3\">\n <RecordingIndicator />\n <span className=\"shrink-0 text-sm text-neutral-foreground tabular-nums\">\n {formatDuration(recordingDuration)}\n </span>\n <LiveWaveform stream={recordingStream} samplesRef={samplesRef} />\n {/* Pause inside the bar — only desktop */}\n <div className=\"hidden sm:contents\">\n <button\n type=\"button\"\n onClick={onPauseRecording}\n className=\"shrink-0 inline-flex items-center justify-center text-neutral-foreground hover:opacity-80 transition-opacity\"\n aria-label=\"Pausar gravacao\"\n >\n <Pause className=\"size-5\" fill=\"currentColor\" strokeWidth={0} />\n </button>\n </div>\n </div>\n\n {/* Send — only inline at desktop */}\n <div className=\"hidden sm:contents\">\n <SendButton onClick={onSendAudio} ariaLabel=\"Enviar audio\" />\n </div>\n </div>\n\n {/* Bottom row — mobile only */}\n <div className=\"flex items-center justify-between sm:hidden\">\n <IconButton\n onClick={onCancelRecording}\n icon={Trash2}\n ariaLabel=\"Cancelar gravacao\"\n />\n <button\n type=\"button\"\n onClick={onPauseRecording}\n className=\"shrink-0 inline-flex items-center justify-center size-10 text-neutral-foreground hover:opacity-80 transition-opacity\"\n aria-label=\"Pausar gravacao\"\n >\n <Pause className=\"size-5\" fill=\"currentColor\" strokeWidth={0} />\n </button>\n <SendButton onClick={onSendAudio} ariaLabel=\"Enviar audio\" />\n </div>\n </div>\n </div>\n )\n }\n\n /* ─── State: paused (com audio gravado) ──────────────────────── */\n if (state === \"paused\") {\n return (\n <div\n data-slot=\"message-bar\"\n data-state=\"paused\"\n className={cn(\n \"flex items-center gap-2 p-2 sm:gap-3 sm:p-0\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-2 w-full sm:contents\">\n <div className=\"flex items-center gap-2 sm:contents\">\n <div className=\"hidden sm:contents\">\n <IconButton\n onClick={onCancelRecording}\n icon={Trash2}\n ariaLabel=\"Cancelar gravacao\"\n />\n </div>\n\n <div className=\"flex items-center gap-3 flex-1 rounded-2xl bg-muted px-4 py-3\">\n <button\n type=\"button\"\n onClick={onTogglePlay}\n className=\"shrink-0 inline-flex items-center justify-center text-neutral-foreground hover:opacity-80 transition-opacity\"\n aria-label={isPlaying ? \"Pausar\" : \"Reproduzir\"}\n >\n {isPlaying ? (\n <Pause className=\"size-5\" fill=\"currentColor\" strokeWidth={0} />\n ) : (\n <Play className=\"size-5\" fill=\"currentColor\" strokeWidth={0} />\n )}\n </button>\n <span className=\"shrink-0 text-sm text-neutral-foreground tabular-nums\">\n {formatDuration(recordingDuration)}\n </span>\n <RecordedWaveform\n samples={samplesRef.current}\n progress={playbackProgress}\n onSeek={onSeekPlayback}\n />\n {/* Mic inline — only desktop */}\n <div className=\"hidden sm:contents\">\n <button\n type=\"button\"\n onClick={onResumeRecording}\n className=\"shrink-0 inline-flex items-center justify-center text-neutral-foreground hover:opacity-80 transition-opacity\"\n aria-label=\"Continuar gravacao\"\n >\n <Mic className=\"size-5\" />\n </button>\n </div>\n </div>\n\n <div className=\"hidden sm:contents\">\n <SendButton onClick={onSendAudio} ariaLabel=\"Enviar audio\" />\n </div>\n </div>\n\n {/* Bottom row — mobile only */}\n <div className=\"flex items-center justify-between sm:hidden\">\n <IconButton\n onClick={onCancelRecording}\n icon={Trash2}\n ariaLabel=\"Cancelar gravacao\"\n />\n <button\n type=\"button\"\n onClick={onResumeRecording}\n className=\"shrink-0 inline-flex items-center justify-center size-10 text-neutral-foreground hover:opacity-80 transition-opacity\"\n aria-label=\"Continuar gravacao\"\n >\n <Mic className=\"size-5\" />\n </button>\n <SendButton onClick={onSendAudio} ariaLabel=\"Enviar audio\" />\n </div>\n </div>\n </div>\n )\n }\n\n /* ─── States: default | active | disabled (input + button) ──── */\n const isDisabled = state === \"disabled\"\n const isActive = state === \"active\" || (state === \"default\" && value.trim().length > 0)\n\n return (\n <div\n data-slot=\"message-bar\"\n data-state={state}\n className={cn(\n \"flex items-center gap-2 rounded-2xl bg-muted p-2\",\n className\n )}\n {...props}\n >\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange?.(e.target.value)}\n onKeyDown={handleKeyDown}\n disabled={isDisabled}\n placeholder={placeholder}\n className={cn(\n \"flex-1 min-w-0 bg-transparent px-3 py-2 text-base text-neutral-foreground placeholder:text-neutral-muted-foreground outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-50\"\n )}\n aria-label=\"Mensagem\"\n />\n {isActive ? (\n <SendButton\n onClick={() => value.trim() && onSendText?.(value)}\n disabled={!value.trim()}\n />\n ) : (\n <MicButton {...pressHandlers} />\n )}\n </div>\n )\n}\n\nexport { MessageBar }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/ui/message-rating.tsx"],"names":[],"mappings":"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","file":"chunk-37C2K2NM.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* ─── Types ───────────────────────────────────────────────────── */\n\nexport type MessageRatingValue = 1 | 2 | 3 | 4 | 5\n\nexport interface RatingLabel {\n emoji: string\n title: string\n subtitle: string\n}\n\nexport type MessageRatingLabels = Record<MessageRatingValue, RatingLabel>\n\nexport interface MessageRatingProps extends Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\"> {\n /** Valor selecionado (controlado) */\n value?: MessageRatingValue | null\n /** Valor inicial (nao controlado) */\n defaultValue?: MessageRatingValue | null\n /** Callback ao escolher uma opcao */\n onChange?: (value: MessageRatingValue) => void\n /** Layout. \"auto\" usa vertical (column) abaixo de sm e horizontal acima */\n layout?: \"horizontal\" | \"vertical\" | \"auto\"\n /** Labels customizadas (default: PT-BR) */\n labels?: Partial<MessageRatingLabels>\n /** Desabilita a interacao */\n disabled?: boolean\n /** Titulo opcional acima das opcoes */\n title?: string\n}\n\n/* ─── Default labels (PT-BR) ──────────────────────────────────── */\n\nconst DEFAULT_LABELS: MessageRatingLabels = {\n 1: { emoji: \"😡\", title: \"Disappointing\", subtitle: \"Decepcionante\" },\n 2: { emoji: \"😞\", title: \"Frustrating\", subtitle: \"Frustrante\" },\n 3: { emoji: \"😐\", title: \"Ok\", subtitle: \"Tudo bem\" },\n 4: { emoji: \"🙂\", title: \"Helpful\", subtitle: \"Ajudou\" },\n 5: { emoji: \"😍\", title: \"Loved it\", subtitle: \"Amei\" },\n}\n\nconst VALUES: MessageRatingValue[] = [1, 2, 3, 4, 5]\n\n/* ─── Component ───────────────────────────────────────────────── */\n\nfunction MessageRating({\n value: controlledValue,\n defaultValue,\n onChange,\n layout = \"auto\",\n labels: labelOverrides,\n disabled = false,\n title,\n className,\n ...props\n}: MessageRatingProps) {\n const [internalValue, setInternalValue] = React.useState<MessageRatingValue | null>(\n defaultValue ?? null\n )\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : internalValue\n\n const labels: MessageRatingLabels = React.useMemo(\n () => ({ ...DEFAULT_LABELS, ...labelOverrides }),\n [labelOverrides]\n )\n\n const handleSelect = (v: MessageRatingValue) => {\n if (disabled) return\n if (!isControlled) setInternalValue(v)\n onChange?.(v)\n }\n\n /* Layout: vertical (column) sobrescreve so essa direcao. horizontal/auto\n sao iguais agora (sempre flex-row, pois mobile e desktop diferem no\n conteudo de cada botao, nao na direcao do container). */\n const layoutClass = layout === \"vertical\" ? \"flex-col\" : \"flex-row\"\n\n return (\n <div\n data-slot=\"message-rating\"\n role=\"radiogroup\"\n aria-label={title ?? \"Avalie sua experiencia\"}\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n >\n {title && (\n <p className=\"text-sm font-medium text-foreground\">{title}</p>\n )}\n <div className={cn(\"flex gap-2\", layoutClass)}>\n {VALUES.map((v) => {\n const label = labels[v]\n const selected = value === v\n return (\n <button\n key={v}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={`${label.title} — ${label.subtitle}`}\n disabled={disabled}\n onClick={() => handleSelect(v)}\n className={cn(\n /* Base — shared mobile/desktop */\n \"flex items-center transition-[color,background-color,border-color,box-shadow] outline-none\",\n \"hover:opacity-90 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n /* Mobile: compacto, justa o emoji centralizado em pill cinza */\n \"rounded-xl px-3 py-2 justify-center\",\n /* Desktop: card completo com texto, flex-1, border */\n \"sm:flex-1 sm:gap-3 sm:px-3 sm:py-2.5 sm:text-left sm:justify-start sm:border\",\n /* Selected vs unselected (estados diferentes por breakpoint) */\n selected\n ? \"bg-accent theme-brand sm:border-primary sm:shadow-xs\"\n : \"bg-muted sm:bg-transparent sm:border-neutral-border\"\n )}\n >\n <span className=\"text-base sm:text-2xl leading-none shrink-0\" aria-hidden=\"true\">\n {label.emoji}\n </span>\n {/* Labels: visiveis apenas no desktop */}\n <span className=\"hidden sm:flex sm:flex-col min-w-0\">\n <span className=\"text-sm font-medium leading-tight text-foreground truncate\">\n {label.title}\n </span>\n <span className=\"text-xs text-muted-foreground leading-tight truncate\">\n {label.subtitle}\n </span>\n </span>\n </button>\n )\n })}\n </div>\n </div>\n )\n}\n\nexport { MessageRating }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/ui/chat-message.tsx"],"names":["_a","waveform"],"mappings":"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","file":"chunk-YMWRR7ET.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Play, Pause } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Avatar, AvatarImage, AvatarFallback } from \"@/components/ui/avatar\"\nimport { LikeDislike, type LikeDislikeValue } from \"@/components/ui/like-dislike\"\nimport { Ai } from \"@/components/icons\"\n\n/* ─── Container variants ──────────────────────────────────────── */\n\nconst chatMessageVariants = cva(\"flex w-full text-sm\", {\n variants: {\n persona: {\n ai: \"justify-start\",\n user: \"justify-end\",\n system: \"justify-center\",\n },\n },\n defaultVariants: {\n persona: \"ai\",\n },\n})\n\n/* ─── Types ───────────────────────────────────────────────────── */\n\nexport interface ChatMessageProps\n extends Omit<React.ComponentProps<\"div\">, \"content\">,\n VariantProps<typeof chatMessageVariants> {\n /** Quem enviou: AI (assistente), user (aluno), system (mensagem do sistema) */\n persona: \"ai\" | \"user\" | \"system\"\n /** Texto da mensagem (opcional se houver apenas audio) */\n text?: string\n /** URL do audio — renderiza AudioPlayer dentro do bubble */\n audioSrc?: string\n /** Avatar do user (so usado em persona=\"user\") */\n avatar?: string\n /** Nome do user para fallback do avatar */\n author?: string\n /** Mostrar like/dislike inline (so faz sentido em persona=\"ai\") */\n showFeedback?: boolean\n /** Valor controlado do feedback */\n feedbackValue?: LikeDislikeValue\n /** Callback quando feedback muda */\n onFeedbackChange?: (value: LikeDislikeValue) => void\n /** Estado de loading: mostra typing indicator (\"...\") */\n loading?: boolean\n}\n\n/* ─── Helpers ─────────────────────────────────────────────────── */\n\nfunction getInitials(name?: string): string {\n if (!name) return \"\"\n return name\n .split(\" \")\n .slice(0, 2)\n .map((w) => w[0])\n .join(\"\")\n .toUpperCase()\n}\n\n/* ─── Typing indicator ────────────────────────────────────────── */\n\nfunction TypingDots() {\n return (\n <span\n className=\"inline-flex items-center gap-1\"\n aria-label=\"Digitando...\"\n role=\"status\"\n >\n <span className=\"size-1.5 rounded-full bg-current opacity-40 animate-bounce [animation-delay:-0.3s]\" />\n <span className=\"size-1.5 rounded-full bg-current opacity-40 animate-bounce [animation-delay:-0.15s]\" />\n <span className=\"size-1.5 rounded-full bg-current opacity-40 animate-bounce\" />\n </span>\n )\n}\n\n/* ─── ChatAudio (compact inline audio player com waveform real) ── */\n\n/** Fallback estatico (valores 0-1) — usado enquanto peaks reais carregam ou quando audio nao pode ser analisado (CORS/decode error) */\nconst STATIC_FALLBACK_PEAKS = [\n 2, 2, 2, 2, 8, 24, 18, 24, 8, 18, 24, 24, 18, 24, 18, 18, 24, 24, 32, 24,\n 24, 32, 24, 32, 32, 24, 18, 24, 24, 18, 24, 18, 18, 24, 24, 24, 24, 24, 32, 24,\n 32, 18, 24, 18, 24, 18, 24, 18, 18, 24, 24, 24, 24, 24, 32, 24, 32, 18, 24, 18,\n 24, 8, 18, 24, 8, 4, 2, 2, 2, 2, 4, 8, 24, 24, 18, 24, 18, 18, 24, 24,\n 32, 24, 24, 32, 24, 32, 32, 24, 18, 24, 24, 18, 24, 8, 18, 24, 8, 2, 2, 4,\n].map((h) => h / 32)\n\nconst MIN_BAR_HEIGHT = 2 // px (silencio)\nconst MAX_BAR_HEIGHT = 32 // px (pico maximo)\nconst BAR_WIDTH = 2 // px (largura fixa de cada barra)\nconst BAR_GAP = 2 // px (espaco entre barras)\nconst SPEED_OPTIONS = [1, 1.25, 1.5, 2, 0.75]\n\n/** Cache modular para evitar re-computar peaks do mesmo audio em multiplas instancias */\nconst peaksCache = new Map<string, number[]>()\n\n/**\n * Calcula picos (amplitude maxima) de um audio dividido em N buckets.\n * Usa Web Audio API (decodeAudioData) — sem dependencias externas.\n * Retorna array de valores 0-1 (normalizado pelo pico maximo).\n */\nasync function calculatePeaks(audioUrl: string, barCount: number): Promise<number[]> {\n const response = await fetch(audioUrl)\n const arrayBuffer = await response.arrayBuffer()\n\n const AudioContextClass =\n window.AudioContext ||\n (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext\n const audioContext = new AudioContextClass()\n const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)\n\n const channelData = audioBuffer.getChannelData(0) // mono ou canal esquerdo\n const samplesPerBar = Math.floor(channelData.length / barCount)\n const peaks: number[] = []\n\n for (let i = 0; i < barCount; i++) {\n const start = i * samplesPerBar\n const end = Math.min(start + samplesPerBar, channelData.length)\n let max = 0\n for (let j = start; j < end; j++) {\n const absSample = Math.abs(channelData[j])\n if (absSample > max) max = absSample\n }\n peaks.push(max)\n }\n\n // Normaliza para 0-1 relativo ao pico maximo do clip\n const maxPeak = Math.max(...peaks, 0.01)\n\n // Fecha o AudioContext (libera recursos)\n void audioContext.close()\n\n return peaks.map((p) => p / maxPeak)\n}\n\n/** Wrapper com cache */\nasync function getPeaks(url: string, barCount: number): Promise<number[]> {\n const cacheKey = `${url}|${barCount}`\n const cached = peaksCache.get(cacheKey)\n if (cached) return cached\n const peaks = await calculatePeaks(url, barCount)\n peaksCache.set(cacheKey, peaks)\n return peaks\n}\n\nfunction formatAudioTime(seconds: number): string {\n if (!Number.isFinite(seconds) || seconds < 0) return \"00:00\"\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return `${m.toString().padStart(2, \"0\")}:${s.toString().padStart(2, \"0\")}`\n}\n\nexport interface ChatAudioProps extends React.ComponentProps<\"div\"> {\n /** URL do audio */\n src: string\n /**\n * Variante visual:\n * - `neutral`: container `bg-muted` (cinza claro) — usado em AI messages\n * - `brand`: container `bg-accent` (rosa pastel) — usado em User messages\n * (requer wrapper `.theme-brand` no componente pai)\n */\n variant?: \"neutral\" | \"brand\"\n /**\n * Array de picos pre-calculados (valores 0-1). Quando fornecido, o componente\n * usa direto sem analisar o audio. Util para SSR, performance ou audios sem CORS.\n * Se nao fornecido, o componente analisa o audio automaticamente via Web Audio API.\n */\n peaks?: number[]\n /**\n * Numero de barras no waveform (default: 60).\n * Ignorado se `peaks` for fornecido (usa o length do array).\n * Reduzido de 100 → 60 para barras nao ficarem finas demais em containers menores.\n */\n barCount?: number\n}\n\nfunction ChatAudio({\n src,\n variant = \"neutral\",\n peaks: providedPeaks,\n barCount = 60,\n className,\n ...props\n}: ChatAudioProps) {\n const audioRef = React.useRef<HTMLAudioElement>(null)\n const [isPlaying, setIsPlaying] = React.useState(false)\n const [currentTime, setCurrentTime] = React.useState(0)\n const [duration, setDuration] = React.useState(0)\n const [speed, setSpeed] = React.useState(1)\n const [computedPeaks, setComputedPeaks] = React.useState<number[] | null>(null)\n\n /** Auto-computa peaks se nao foram fornecidos */\n React.useEffect(() => {\n if (providedPeaks) return // consumer ja forneceu, skip analise\n let cancelled = false\n getPeaks(src, barCount)\n .then((p) => {\n if (!cancelled) setComputedPeaks(p)\n })\n .catch((err) => {\n /* fallback silencioso: mantem null, usa fallback estatico.\n Causa comum: CORS (audio source nao tem Access-Control-Allow-Origin).\n Log apenas em dev para nao poluir prod. */\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[ChatAudio] Failed to analyze waveform for \"${src}\". ` +\n `Falling back to static waveform. ` +\n `Reason: ${err instanceof Error ? err.message : String(err)}. ` +\n `Audio source likely missing CORS headers (Access-Control-Allow-Origin).`\n )\n }\n })\n return () => {\n cancelled = true\n }\n }, [src, providedPeaks, barCount])\n\n /** Fallback estatico ajustado para o barCount atual (evita troca visual brusca quando peaks reais carregam) */\n const fallbackPeaks = React.useMemo(() => {\n return Array.from(\n { length: barCount },\n (_, i) => STATIC_FALLBACK_PEAKS[i % STATIC_FALLBACK_PEAKS.length]\n )\n }, [barCount])\n\n /** Resolve peaks: provided > computed > fallback (ajustado por barCount) */\n const peaks = providedPeaks ?? computedPeaks ?? fallbackPeaks\n\n /** Seta duracao apenas se valor for finito e positivo (evita Infinity/NaN) */\n const setDurationSafe = React.useCallback((value: number) => {\n if (Number.isFinite(value) && value > 0) {\n setDuration((prev) => (prev !== value ? value : prev))\n }\n }, [])\n\n /** Subscribe a multiplos eventos para garantir captura da duracao\n * (alguns audio sources nao disparam loadedmetadata, so durationchange/canplay) */\n React.useEffect(() => {\n const audio = audioRef.current\n if (!audio) return\n\n const handleDuration = () => setDurationSafe(audio.duration)\n handleDuration() // checa se ja esta carregado\n\n audio.addEventListener(\"loadedmetadata\", handleDuration)\n audio.addEventListener(\"durationchange\", handleDuration)\n audio.addEventListener(\"canplay\", handleDuration)\n return () => {\n audio.removeEventListener(\"loadedmetadata\", handleDuration)\n audio.removeEventListener(\"durationchange\", handleDuration)\n audio.removeEventListener(\"canplay\", handleDuration)\n }\n }, [src, setDurationSafe])\n\n const togglePlay = () => {\n const audio = audioRef.current\n if (!audio) return\n if (audio.paused) {\n audio.play().catch(() => {})\n } else {\n audio.pause()\n }\n }\n\n const cycleSpeed = () => {\n const idx = SPEED_OPTIONS.indexOf(speed)\n const next = SPEED_OPTIONS[(idx + 1) % SPEED_OPTIONS.length] ?? 1\n setSpeed(next)\n if (audioRef.current) audioRef.current.playbackRate = next\n }\n\n /* ─── Seek/drag via pointer no waveform ───────────────────── */\n\n const waveformRef = React.useRef<HTMLDivElement>(null)\n const isDraggingRef = React.useRef(false)\n\n /** Converte clientX (event) em time do audio, baseado na largura do layout de barras */\n const seekToClientX = React.useCallback(\n (clientX: number) => {\n const audio = audioRef.current\n const waveform = waveformRef.current\n if (!audio || !waveform || !duration) return\n const rect = waveform.getBoundingClientRect()\n const x = clientX - rect.left\n const newProgress = Math.max(\n 0,\n Math.min(x / (peaks.length * (BAR_WIDTH + BAR_GAP) - BAR_GAP), 1)\n )\n audio.currentTime = newProgress * duration\n },\n [duration, peaks.length]\n )\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!duration) return\n isDraggingRef.current = true\n e.currentTarget.setPointerCapture(e.pointerId)\n seekToClientX(e.clientX)\n }\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDraggingRef.current) return\n seekToClientX(e.clientX)\n }\n\n const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDraggingRef.current) return\n isDraggingRef.current = false\n e.currentTarget.releasePointerCapture(e.pointerId)\n }\n\n const progress = duration > 0 ? currentTime / duration : 0\n const displayTime = formatAudioTime(currentTime)\n\n /**\n * Largura natural do layout de barras (em px):\n * - N barras de BAR_WIDTH + (N-1) gaps de BAR_GAP\n * Usado para posicionar a bolinha e calcular seek por click/drag.\n */\n const barsLayoutWidth = peaks.length * (BAR_WIDTH + BAR_GAP) - BAR_GAP\n\n /* Waveform JSX — reusado entre layouts mobile (top) e desktop (inline).\n Barras com largura FIXA de 2px (matches Figma). Layout pode overflowar\n em containers narrow; overflow-hidden clipa a direita.\n Pointer events permitem clicar/arrastar para seek. */\n const waveform = (\n <div\n ref={waveformRef}\n className=\"flex-1 relative h-8 min-w-0 overflow-hidden touch-none cursor-pointer select-none\"\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n role=\"slider\"\n aria-label=\"Posicao do audio\"\n aria-valuemin={0}\n aria-valuemax={Math.round(duration)}\n aria-valuenow={Math.round(currentTime)}\n >\n <div className=\"absolute inset-y-0 left-0 flex items-center gap-[2px]\">\n {peaks.map((peak, i) => {\n const isPlayed = i / peaks.length <= progress\n const height = Math.max(\n MIN_BAR_HEIGHT,\n Math.round(peak * MAX_BAR_HEIGHT)\n )\n return (\n <div\n key={i}\n className={cn(\n \"w-[2px] shrink-0 rounded-full\",\n isPlayed ? \"bg-neutral-foreground\" : \"bg-neutral-ring\"\n )}\n style={{ height: `${height}px` }}\n />\n )\n })}\n </div>\n {/* Bolinha verde — posicionada em PIXELS reais relativos ao layout das barras\n (matches exatamente a transicao played/unplayed). */}\n {duration > 0 && (\n <div\n className=\"absolute top-1/2 z-10 -translate-y-1/2 -translate-x-1/2 size-3 rounded-full bg-[#098A5E] pointer-events-none shadow-md\"\n style={{ left: `${progress * barsLayoutWidth}px` }}\n aria-hidden=\"true\"\n />\n )}\n </div>\n )\n\n /* Time display — reusado entre layouts */\n const timeDisplay = (\n <span className=\"shrink-0 text-sm text-neutral-ring tabular-nums\">\n {displayTime}\n </span>\n )\n\n /* Speed badge — reusado entre layouts */\n const speedBadge = (\n <button\n type=\"button\"\n onClick={cycleSpeed}\n className={cn(\n \"shrink-0 h-[26px] min-w-16 rounded-full text-sm font-medium px-2 transition-opacity hover:opacity-80\",\n variant === \"brand\"\n ? \"bg-muted text-muted-foreground\"\n : \"bg-background text-neutral-muted-foreground\"\n )}\n aria-label={`Velocidade ${speed}x. Clique para alternar.`}\n >\n {speed === 1 ? \"1x\" : `${speed}x`}\n </button>\n )\n\n return (\n <div\n data-slot=\"chat-audio\"\n className={cn(\n \"rounded-2xl w-full max-w-md flex flex-col gap-2 p-3 sm:flex-row sm:items-center sm:gap-2 sm:pl-5 sm:pr-3 sm:py-3\",\n variant === \"brand\" ? \"bg-accent\" : \"bg-muted\",\n className\n )}\n {...props}\n >\n <audio\n ref={audioRef}\n src={src}\n preload=\"metadata\"\n onPlay={() => setIsPlaying(true)}\n onPause={() => setIsPlaying(false)}\n onTimeUpdate={(e) => {\n setCurrentTime(e.currentTarget.currentTime)\n /* Fallback: alguns sources so expoem duration durante o playback */\n setDurationSafe(e.currentTarget.duration)\n }}\n onEnded={() => setIsPlaying(false)}\n />\n\n {/* Mobile top row + Desktop inline row */}\n <div className=\"flex items-center gap-2 flex-1 min-w-0\">\n {/* Play/Pause — icones FILLED */}\n <button\n type=\"button\"\n onClick={togglePlay}\n className=\"shrink-0 flex items-center justify-center text-neutral-foreground hover:opacity-80 transition-opacity\"\n aria-label={isPlaying ? \"Pausar\" : \"Reproduzir\"}\n >\n {isPlaying ? (\n <Pause className=\"size-4\" fill=\"currentColor\" strokeWidth={0} />\n ) : (\n <Play className=\"size-4\" fill=\"currentColor\" strokeWidth={0} />\n )}\n </button>\n\n {/* Time — apenas desktop (no mobile aparece embaixo) */}\n <div className=\"hidden sm:contents\">{timeDisplay}</div>\n\n {waveform}\n\n {/* Speed — apenas desktop (no mobile aparece embaixo) */}\n <div className=\"hidden sm:contents\">{speedBadge}</div>\n </div>\n\n {/* Mobile bottom row: time + speed badge */}\n <div className=\"flex items-center justify-between sm:hidden\">\n {timeDisplay}\n {speedBadge}\n </div>\n </div>\n )\n}\n\nexport { ChatAudio }\n\n/* ─── Component ───────────────────────────────────────────────── */\n\nfunction ChatMessage({\n persona,\n text,\n audioSrc,\n avatar,\n author,\n showFeedback = false,\n feedbackValue,\n onFeedbackChange,\n loading = false,\n className,\n ...props\n}: ChatMessageProps) {\n /* System: centered italic */\n if (persona === \"system\") {\n return (\n <div\n data-slot=\"chat-message\"\n data-persona=\"system\"\n className={cn(chatMessageVariants({ persona }), className)}\n {...props}\n >\n <span className=\"text-xs text-muted-foreground italic\">{text}</span>\n </div>\n )\n }\n\n /* AI: badge quadrado (esquerda, apenas desktop) + conteudo empilhado */\n if (persona === \"ai\") {\n return (\n <div\n data-slot=\"chat-message\"\n data-persona=\"ai\"\n className={cn(chatMessageVariants({ persona }), className)}\n {...props}\n >\n <div className=\"flex gap-3 max-w-[85%] sm:max-w-[75%] w-full\">\n {/* AI badge: oculto no mobile, visivel no desktop */}\n <div className=\"hidden sm:flex shrink-0 size-8 rounded-md bg-primary items-center justify-center theme-brand\">\n <span className=\"text-primary-foreground\">\n <Ai size=\"sm\" decorative />\n </span>\n </div>\n <div className=\"flex flex-col gap-2 min-w-0 flex-1\">\n {loading ? (\n /* Loading: dots dentro de bubble cinza (speech bubble shape — top-left reto) */\n <div className=\"self-start inline-flex items-center rounded-2xl sm:rounded-tl-none bg-muted p-5 text-muted-foreground\">\n <TypingDots />\n </div>\n ) : (\n <>\n {text && (\n /* Text bubble: bg-muted sempre, speech bubble shape (tl-none) apenas no desktop */\n <div className=\"rounded-2xl bg-muted p-5 sm:rounded-tl-none\">\n <p className=\"text-base leading-6 text-neutral-foreground break-words\">{text}</p>\n </div>\n )}\n {audioSrc && <ChatAudio src={audioSrc} variant=\"neutral\" />}\n {showFeedback && (\n <LikeDislike\n size=\"xs\"\n value={feedbackValue}\n onValueChange={onFeedbackChange}\n />\n )}\n </>\n )}\n </div>\n </div>\n </div>\n )\n }\n\n /* User: bubble (direita) + avatar (apenas desktop, alinhado ao topo) */\n return (\n <div\n data-slot=\"chat-message\"\n data-persona=\"user\"\n className={cn(chatMessageVariants({ persona }), className)}\n {...props}\n >\n <div className=\"flex items-start gap-3 max-w-[85%] sm:max-w-[75%] w-full justify-end\">\n <div className=\"flex flex-col gap-2 min-w-0 items-end theme-brand flex-1\">\n {loading ? (\n /* Loading: dots dentro de bubble pink (speech bubble shape — top-right reto) */\n <div className=\"inline-flex items-center rounded-2xl sm:rounded-tr-none bg-accent p-5 text-neutral-muted-foreground\">\n <TypingDots />\n </div>\n ) : (\n <>\n {text && (\n /* Text bubble: speech bubble shape (top-right reto) no desktop.\n text-neutral-foreground = preto neutro fixo, nao muda com theme-brand */\n <div className=\"rounded-2xl sm:rounded-tr-none bg-accent p-5\">\n <p className=\"text-base leading-6 text-neutral-foreground break-words\">{text}</p>\n </div>\n )}\n {audioSrc && <ChatAudio src={audioSrc} variant=\"brand\" />}\n </>\n )}\n </div>\n {/* Avatar: 40x40 rounded-lg, oculto no mobile, alinhado ao topo */}\n <Avatar size=\"lg\" className=\"hidden sm:flex shrink-0 rounded-lg\">\n {avatar && (\n <AvatarImage src={avatar} alt={author ?? \"User\"} className=\"rounded-lg\" />\n )}\n <AvatarFallback className=\"rounded-lg bg-muted text-muted-foreground text-sm\">\n {getInitials(author)}\n </AvatarFallback>\n </Avatar>\n </div>\n </div>\n )\n}\n\nexport { ChatMessage, chatMessageVariants }\n"]}