@fluencypassdevs/cycle 1.9.1 → 1.9.7

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.
@@ -23,11 +23,23 @@ function MicButton({
23
23
  className,
24
24
  style
25
25
  }) {
26
+ const buttonRef = React.useRef(null);
27
+ const hasPressFlow = !!onPointerDown;
28
+ React.useEffect(() => {
29
+ const btn = buttonRef.current;
30
+ if (!btn || !hasPressFlow) return;
31
+ const onTouchStart = (e) => {
32
+ e.preventDefault();
33
+ };
34
+ btn.addEventListener("touchstart", onTouchStart, { passive: false });
35
+ return () => btn.removeEventListener("touchstart", onTouchStart);
36
+ }, [hasPressFlow]);
26
37
  const sizeClass = variant === "large" ? "size-16" : size === "default" ? "size-10" : "size-8";
27
38
  const radiusClass = variant === "large" ? "rounded-lg" : "rounded-md";
28
39
  return /* @__PURE__ */ jsx(
29
40
  "button",
30
41
  {
42
+ ref: buttonRef,
31
43
  type: "button",
32
44
  onClick,
33
45
  onPointerDown,
@@ -39,7 +51,10 @@ function MicButton({
39
51
  "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",
40
52
  sizeClass,
41
53
  radiusClass,
42
- pressed && "opacity-90 touch-none select-none",
54
+ pressed && "opacity-90 select-none",
55
+ // touch-none aplicado sempre que ha press flow (nao so quando ja esta pressed),
56
+ // pra Android Chrome nao classificar o touchstart como scroll
57
+ (hasPressFlow || pressed) && "touch-none",
43
58
  className
44
59
  ),
45
60
  style,
@@ -305,24 +320,40 @@ function RecordedWaveform({
305
320
  }
306
321
  );
307
322
  }
323
+ var LOCK_THRESHOLD = 120;
324
+ var CANCEL_THRESHOLD_RATIO = 0.65;
325
+ var CANCEL_THRESHOLD_MIN = 140;
326
+ var CANCEL_THRESHOLD_MAX = 220;
308
327
  var MIN_DURATION = 1e3;
328
+ function computeCancelThreshold(containerWidth) {
329
+ return Math.min(
330
+ CANCEL_THRESHOLD_MAX,
331
+ Math.max(CANCEL_THRESHOLD_MIN, containerWidth * CANCEL_THRESHOLD_RATIO)
332
+ );
333
+ }
309
334
  function PressedRecordingOverlay({
310
335
  variant,
311
336
  duration,
312
337
  deltaX,
313
- deltaY
338
+ deltaY,
339
+ lockThreshold,
340
+ cancelThreshold
314
341
  }) {
315
- const aboutToLock = deltaY <= -60;
316
- const aboutToCancel = deltaX <= -80;
317
- const micTranslateX = Math.min(0, deltaX);
318
- const micTranslateY = Math.min(0, deltaY);
342
+ const aboutToLock = deltaY <= -lockThreshold;
343
+ const aboutToCancel = deltaX <= -cancelThreshold;
344
+ const clampedX = Math.min(0, deltaX);
345
+ const clampedY = Math.min(0, deltaY);
346
+ const absX = Math.abs(clampedX);
347
+ const absY = Math.abs(clampedY);
348
+ const micTranslateX = absX >= absY ? clampedX : 0;
349
+ const micTranslateY = absY > absX ? clampedY : 0;
319
350
  return /* @__PURE__ */ jsx(
320
351
  "div",
321
352
  {
322
353
  "data-slot": "message-bar",
323
354
  "data-state": "recording-pressed",
324
355
  className: cn(
325
- "flex items-center gap-2 p-2 sm:gap-3 sm:p-0",
356
+ "flex items-center gap-2 p-2 sm:gap-3 sm:p-0 touch-none select-none",
326
357
  variant === "audio-only" && "justify-center"
327
358
  ),
328
359
  children: variant === "audio-only" ? /* @__PURE__ */ jsxs("div", { className: "relative flex items-center gap-2", children: [
@@ -495,8 +526,11 @@ function MessageBar(_a) {
495
526
  }, [state]);
496
527
  const [isPressed, setIsPressed] = React.useState(false);
497
528
  const [pressDelta, setPressDelta] = React.useState({ x: 0, y: 0 });
529
+ const [pressCancelThreshold, setPressCancelThreshold] = React.useState(CANCEL_THRESHOLD_MAX);
498
530
  const pressDeltaRef = React.useRef({ x: 0, y: 0 });
531
+ const pressCancelThresholdRef = React.useRef(CANCEL_THRESHOLD_MAX);
499
532
  const pressInfoRef = React.useRef({ startX: 0, startY: 0, startTime: 0, locked: false });
533
+ const isPressedRef = React.useRef(false);
500
534
  const callbacksRef = React.useRef({ onStartRecording, onCancelRecording, onSendAudio });
501
535
  React.useEffect(() => {
502
536
  callbacksRef.current = { onStartRecording, onCancelRecording, onSendAudio };
@@ -505,6 +539,15 @@ function MessageBar(_a) {
505
539
  pressDeltaRef.current = { x: dx, y: dy };
506
540
  setPressDelta({ x: dx, y: dy });
507
541
  };
542
+ React.useEffect(() => {
543
+ const onTouchMove = (e) => {
544
+ if (isPressedRef.current) {
545
+ e.preventDefault();
546
+ }
547
+ };
548
+ window.addEventListener("touchmove", onTouchMove, { passive: false });
549
+ return () => window.removeEventListener("touchmove", onTouchMove);
550
+ }, []);
508
551
  const triggerHaptic = (ms = 50) => {
509
552
  if (typeof navigator !== "undefined" && typeof navigator.vibrate === "function") {
510
553
  try {
@@ -513,15 +556,22 @@ function MessageBar(_a) {
513
556
  }
514
557
  }
515
558
  };
559
+ React.useEffect(() => {
560
+ isPressedRef.current = isPressed;
561
+ }, [isPressed]);
516
562
  React.useEffect(() => {
517
563
  if (!isPressed) return;
564
+ const prevHtmlTouchAction = document.documentElement.style.touchAction;
565
+ const prevBodyTouchAction = document.body.style.touchAction;
566
+ document.documentElement.style.touchAction = "none";
567
+ document.body.style.touchAction = "none";
518
568
  const onMove = (e) => {
519
569
  if (pressInfoRef.current.locked) return;
520
570
  const { startX, startY } = pressInfoRef.current;
521
571
  const dx = e.clientX - startX;
522
572
  const dy = e.clientY - startY;
523
573
  updateDelta(dx, dy);
524
- if (dy <= -60) {
574
+ if (dy <= -LOCK_THRESHOLD) {
525
575
  pressInfoRef.current.locked = true;
526
576
  triggerHaptic(50);
527
577
  setIsPressed(false);
@@ -536,7 +586,7 @@ function MessageBar(_a) {
536
586
  const { x: dx } = pressDeltaRef.current;
537
587
  setIsPressed(false);
538
588
  updateDelta(0, 0);
539
- if (dx <= -80 || elapsed < MIN_DURATION) {
589
+ if (dx <= -pressCancelThresholdRef.current || elapsed < MIN_DURATION) {
540
590
  triggerHaptic(50);
541
591
  (_b2 = (_a2 = callbacksRef.current).onCancelRecording) == null ? void 0 : _b2.call(_a2);
542
592
  return;
@@ -550,6 +600,8 @@ function MessageBar(_a) {
550
600
  window.removeEventListener("pointermove", onMove);
551
601
  window.removeEventListener("pointerup", onEnd);
552
602
  window.removeEventListener("pointercancel", onEnd);
603
+ document.documentElement.style.touchAction = prevHtmlTouchAction;
604
+ document.body.style.touchAction = prevBodyTouchAction;
553
605
  };
554
606
  }, [isPressed]);
555
607
  const handlePressStart = (e) => {
@@ -557,6 +609,11 @@ function MessageBar(_a) {
557
609
  onStartRecording == null ? void 0 : onStartRecording();
558
610
  return;
559
611
  }
612
+ const wrapper = e.currentTarget.closest('[data-slot="message-bar"]');
613
+ const containerWidth = wrapper instanceof HTMLElement ? wrapper.clientWidth : window.innerWidth;
614
+ const threshold = computeCancelThreshold(containerWidth);
615
+ pressCancelThresholdRef.current = threshold;
616
+ setPressCancelThreshold(threshold);
560
617
  pressInfoRef.current = {
561
618
  startX: e.clientX,
562
619
  startY: e.clientY,
@@ -595,7 +652,9 @@ function MessageBar(_a) {
595
652
  variant: lastBaseStateRef.current,
596
653
  duration: recordingDuration,
597
654
  deltaX: pressDelta.x,
598
- deltaY: pressDelta.y
655
+ deltaY: pressDelta.y,
656
+ lockThreshold: LOCK_THRESHOLD,
657
+ cancelThreshold: pressCancelThreshold
599
658
  }
600
659
  );
601
660
  }
@@ -783,5 +842,5 @@ function MessageBar(_a) {
783
842
  }
784
843
 
785
844
  export { MessageBar };
786
- //# sourceMappingURL=chunk-S3XRCFLJ.js.map
787
- //# sourceMappingURL=chunk-S3XRCFLJ.js.map
845
+ //# sourceMappingURL=chunk-27PO7X4G.js.map
846
+ //# sourceMappingURL=chunk-27PO7X4G.js.map
@@ -0,0 +1 @@
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"]}
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ export { Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHead
18
18
  export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './chunk-IGMII4BK.js';
19
19
  export { ChatAudio, ChatMessage, chatMessageVariants } from './chunk-YMWRR7ET.js';
20
20
  export { MessageRating } from './chunk-37C2K2NM.js';
21
- export { MessageBar } from './chunk-S3XRCFLJ.js';
21
+ export { MessageBar } from './chunk-27PO7X4G.js';
22
22
  export { ChatPanel } from './chunk-L32AMI4K.js';
23
23
  export { ChatBubble, chatBubbleVariants } from './chunk-HZJRM5EK.js';
24
24
  export { LikeDislike, likeDislikeVariants } from './chunk-F2XA2Z75.js';
@@ -1,4 +1,4 @@
1
- export { MessageBar } from '../chunk-S3XRCFLJ.js';
1
+ export { MessageBar } from '../chunk-27PO7X4G.js';
2
2
  import '../chunk-TYCPXAXF.js';
3
3
  import '../chunk-YINJ5YZ5.js';
4
4
  //# sourceMappingURL=message-bar.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluencypassdevs/cycle",
3
- "version": "1.9.1",
3
+ "version": "1.9.7",
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-S3XRCFLJ.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 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 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 touch-none select-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 = 60 // px arrastados pra cima → trava em modo hands-free\nconst CANCEL_THRESHOLD = 80 // px arrastados pra esquerda → cancela (valor absoluto)\nconst MIN_DURATION = 1000 // ms — release antes disso cancela\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}: {\n variant: \"default\" | \"audio-only\"\n duration: number\n deltaX: number\n deltaY: number\n}) {\n const aboutToLock = deltaY <= -LOCK_THRESHOLD\n const aboutToCancel = deltaX <= -CANCEL_THRESHOLD\n // Clamp: so move pra cima/esquerda (delta negativo); ignora positivos\n const micTranslateX = Math.min(0, deltaX)\n const micTranslateY = Math.min(0, deltaY)\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\",\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 const pressDeltaRef = React.useRef({ x: 0, y: 0 })\n const pressInfoRef = React.useRef({ startX: 0, startY: 0, startTime: 0, locked: 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 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 React.useEffect(() => {\n if (!isPressed) return\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 <= -CANCEL_THRESHOLD || 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 window.addEventListener(\"pointercancel\", onEnd)\n return () => {\n window.removeEventListener(\"pointermove\", onMove)\n window.removeEventListener(\"pointerup\", onEnd)\n window.removeEventListener(\"pointercancel\", onEnd)\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 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 />\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"]}