@fluencypassdevs/cycle 1.10.0 → 1.15.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.
- package/bin/mcp.mjs +225 -9
- package/dist/chunk-5HPZCREI.js +55 -0
- package/dist/chunk-5HPZCREI.js.map +1 -0
- package/dist/chunk-6JH4YWWX.js +29 -0
- package/dist/chunk-6JH4YWWX.js.map +1 -0
- package/dist/chunk-7LH7PSQS.js +77 -0
- package/dist/chunk-7LH7PSQS.js.map +1 -0
- package/dist/{chunk-YMWRR7ET.js → chunk-CG7NXMBC.js} +18 -23
- package/dist/chunk-CG7NXMBC.js.map +1 -0
- package/dist/{chunk-27PO7X4G.js → chunk-CWMXYPWK.js} +101 -11
- package/dist/chunk-CWMXYPWK.js.map +1 -0
- package/dist/chunk-EACBYVLK.js +29 -0
- package/dist/chunk-EACBYVLK.js.map +1 -0
- package/dist/chunk-HDCU6QSG.js +24 -0
- package/dist/chunk-HDCU6QSG.js.map +1 -0
- package/dist/{chunk-U4QKU5RB.js → chunk-JGUDRAWA.js} +81 -23
- package/dist/chunk-JGUDRAWA.js.map +1 -0
- package/dist/chunk-K2NUBNSA.js +17 -0
- package/dist/chunk-K2NUBNSA.js.map +1 -0
- package/dist/chunk-NW56QDQM.js +64 -0
- package/dist/chunk-NW56QDQM.js.map +1 -0
- package/dist/chunk-NZXP7BAH.js +33 -0
- package/dist/chunk-NZXP7BAH.js.map +1 -0
- package/dist/chunk-TPRZMMT6.js +57 -0
- package/dist/chunk-TPRZMMT6.js.map +1 -0
- package/dist/chunk-UJ6OER6O.js +49 -0
- package/dist/chunk-UJ6OER6O.js.map +1 -0
- package/dist/chunk-VXWMC2NK.js +24 -0
- package/dist/chunk-VXWMC2NK.js.map +1 -0
- package/dist/chunk-VYHRNO77.js +27 -0
- package/dist/chunk-VYHRNO77.js.map +1 -0
- package/dist/chunk-XHKFKLHD.js +26 -0
- package/dist/chunk-XHKFKLHD.js.map +1 -0
- package/dist/chunk-XQUQDZVA.js +36 -0
- package/dist/chunk-XQUQDZVA.js.map +1 -0
- package/dist/composites/chat-thread.d.ts +27 -2
- package/dist/composites/chat-thread.js +3 -3
- package/dist/hooks/use-intersection.d.ts +34 -0
- package/dist/hooks/use-intersection.js +4 -0
- package/dist/hooks/use-intersection.js.map +1 -0
- package/dist/hooks/use-reduced-motion.d.ts +11 -0
- package/dist/hooks/use-reduced-motion.js +4 -0
- package/dist/hooks/use-reduced-motion.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/marketing/effects/card-dark-glow.d.ts +30 -0
- package/dist/marketing/effects/card-dark-glow.js +5 -0
- package/dist/marketing/effects/card-dark-glow.js.map +1 -0
- package/dist/marketing/effects/circle-glow.d.ts +26 -0
- package/dist/marketing/effects/circle-glow.js +5 -0
- package/dist/marketing/effects/circle-glow.js.map +1 -0
- package/dist/marketing/effects/index.d.ts +4 -0
- package/dist/marketing/effects/index.js +7 -0
- package/dist/marketing/effects/index.js.map +1 -0
- package/dist/marketing/effects/marquee.d.ts +30 -0
- package/dist/marketing/effects/marquee.js +5 -0
- package/dist/marketing/effects/marquee.js.map +1 -0
- package/dist/marketing/layout/index.d.ts +2 -0
- package/dist/marketing/layout/index.js +5 -0
- package/dist/marketing/layout/index.js.map +1 -0
- package/dist/marketing/layout/section.d.ts +36 -0
- package/dist/marketing/layout/section.js +5 -0
- package/dist/marketing/layout/section.js.map +1 -0
- package/dist/marketing/motion/animated-number.d.ts +35 -0
- package/dist/marketing/motion/animated-number.js +7 -0
- package/dist/marketing/motion/animated-number.js.map +1 -0
- package/dist/marketing/motion/index.d.ts +6 -0
- package/dist/marketing/motion/index.js +10 -0
- package/dist/marketing/motion/index.js.map +1 -0
- package/dist/marketing/motion/reveal-on-scroll.d.ts +27 -0
- package/dist/marketing/motion/reveal-on-scroll.js +7 -0
- package/dist/marketing/motion/reveal-on-scroll.js.map +1 -0
- package/dist/marketing/motion/smooth-anchor.d.ts +31 -0
- package/dist/marketing/motion/smooth-anchor.js +4 -0
- package/dist/marketing/motion/smooth-anchor.js.map +1 -0
- package/dist/marketing/motion/stagger-reveal.d.ts +30 -0
- package/dist/marketing/motion/stagger-reveal.js +7 -0
- package/dist/marketing/motion/stagger-reveal.js.map +1 -0
- package/dist/marketing/typography/hero-heading.d.ts +25 -0
- package/dist/marketing/typography/hero-heading.js +5 -0
- package/dist/marketing/typography/hero-heading.js.map +1 -0
- package/dist/marketing/typography/index.d.ts +5 -0
- package/dist/marketing/typography/index.js +8 -0
- package/dist/marketing/typography/index.js.map +1 -0
- package/dist/marketing/typography/section-eyebrow.d.ts +21 -0
- package/dist/marketing/typography/section-eyebrow.js +5 -0
- package/dist/marketing/typography/section-eyebrow.js.map +1 -0
- package/dist/marketing/typography/section-heading.d.ts +37 -0
- package/dist/marketing/typography/section-heading.js +5 -0
- package/dist/marketing/typography/section-heading.js.map +1 -0
- package/dist/marketing/typography/section-subtitle.d.ts +19 -0
- package/dist/marketing/typography/section-subtitle.js +5 -0
- package/dist/marketing/typography/section-subtitle.js.map +1 -0
- package/dist/styles/tokens.css +192 -0
- package/dist/ui/chat-message.d.ts +7 -2
- package/dist/ui/chat-message.js +1 -1
- package/dist/ui/message-bar.d.ts +24 -1
- package/dist/ui/message-bar.js +1 -1
- package/package.json +37 -1
- package/dist/chunk-27PO7X4G.js.map +0 -1
- package/dist/chunk-U4QKU5RB.js.map +0 -1
- package/dist/chunk-YMWRR7ET.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from './chunk-3EFI7PYC.js';
|
|
2
|
-
import { ChatMessage } from './chunk-
|
|
2
|
+
import { ChatMessage } from './chunk-CG7NXMBC.js';
|
|
3
3
|
import { DEFAULT_MESSAGE_RATING_LABELS, MessageRating } from './chunk-6OYSTCGP.js';
|
|
4
|
-
import { MessageBar } from './chunk-
|
|
4
|
+
import { MessageBar } from './chunk-CWMXYPWK.js';
|
|
5
5
|
import { cn } from './chunk-TYCPXAXF.js';
|
|
6
6
|
import { __objRest, __spreadValues, __spreadProps } from './chunk-YINJ5YZ5.js';
|
|
7
7
|
import * as React from 'react';
|
|
@@ -96,6 +96,32 @@ function MessageBubbleAnimated({
|
|
|
96
96
|
}
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
|
+
var LEAVE_DURATION_MS = 150;
|
|
100
|
+
function BottomSlot({
|
|
101
|
+
kind,
|
|
102
|
+
messageBar,
|
|
103
|
+
stopButton
|
|
104
|
+
}) {
|
|
105
|
+
const [rendered, setRendered] = React.useState(kind);
|
|
106
|
+
const [phase, setPhase] = React.useState("enter");
|
|
107
|
+
React.useEffect(() => {
|
|
108
|
+
if (rendered === kind) return;
|
|
109
|
+
setPhase("leave");
|
|
110
|
+
const t = setTimeout(() => {
|
|
111
|
+
setRendered(kind);
|
|
112
|
+
setPhase("enter");
|
|
113
|
+
}, LEAVE_DURATION_MS);
|
|
114
|
+
return () => clearTimeout(t);
|
|
115
|
+
}, [kind, rendered]);
|
|
116
|
+
return /* @__PURE__ */ jsx("div", { className: "shrink-0 px-4 pb-4 pt-2", children: rendered !== "hidden" && /* @__PURE__ */ jsx(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
className: phase === "enter" ? "animate-thread-msg-enter" : "animate-thread-msg-leave",
|
|
120
|
+
children: rendered === "messagebar" ? messageBar : stopButton
|
|
121
|
+
},
|
|
122
|
+
rendered
|
|
123
|
+
) });
|
|
124
|
+
}
|
|
99
125
|
function ChatThread(_a) {
|
|
100
126
|
var _b = _a, {
|
|
101
127
|
messages,
|
|
@@ -127,6 +153,12 @@ function ChatThread(_a) {
|
|
|
127
153
|
placeholder,
|
|
128
154
|
maxLength,
|
|
129
155
|
audioOnlyMode = false,
|
|
156
|
+
maxRecordingDuration,
|
|
157
|
+
warnAtSecondsLeft,
|
|
158
|
+
secondsLeftLabel,
|
|
159
|
+
onMaxDurationReached,
|
|
160
|
+
userAvatar,
|
|
161
|
+
userName,
|
|
130
162
|
offlineBannerText = "Sem conexao. Tentando reconectar...",
|
|
131
163
|
retryButtonText = "Tentar novamente",
|
|
132
164
|
regenerateButtonText = "Regenerar resposta",
|
|
@@ -163,6 +195,12 @@ function ChatThread(_a) {
|
|
|
163
195
|
"placeholder",
|
|
164
196
|
"maxLength",
|
|
165
197
|
"audioOnlyMode",
|
|
198
|
+
"maxRecordingDuration",
|
|
199
|
+
"warnAtSecondsLeft",
|
|
200
|
+
"secondsLeftLabel",
|
|
201
|
+
"onMaxDurationReached",
|
|
202
|
+
"userAvatar",
|
|
203
|
+
"userName",
|
|
166
204
|
"offlineBannerText",
|
|
167
205
|
"retryButtonText",
|
|
168
206
|
"regenerateButtonText",
|
|
@@ -284,6 +322,13 @@ function ChatThread(_a) {
|
|
|
284
322
|
setInternalRecordingState("idle");
|
|
285
323
|
onSendAudio == null ? void 0 : onSendAudio();
|
|
286
324
|
}, [onSendAudio]);
|
|
325
|
+
const handleMaxDurationInternal = React.useCallback(() => {
|
|
326
|
+
if (onMaxDurationReached) {
|
|
327
|
+
onMaxDurationReached();
|
|
328
|
+
} else {
|
|
329
|
+
handlePauseRecordingInternal();
|
|
330
|
+
}
|
|
331
|
+
}, [onMaxDurationReached, handlePauseRecordingInternal]);
|
|
287
332
|
const [inputValue, setInputValue] = React.useState("");
|
|
288
333
|
const handleSendTextInternal = React.useCallback(
|
|
289
334
|
(text) => {
|
|
@@ -329,6 +374,8 @@ function ChatThread(_a) {
|
|
|
329
374
|
persona: msg.persona,
|
|
330
375
|
text: msg.text,
|
|
331
376
|
audioSrc: msg.audioSrc,
|
|
377
|
+
avatar: msg.persona === "user" ? userAvatar : void 0,
|
|
378
|
+
author: msg.persona === "user" ? userName : void 0,
|
|
332
379
|
loading: isPendingUser && !msg.text && !msg.audioSrc,
|
|
333
380
|
className: cn(
|
|
334
381
|
isPendingUser && "opacity-80",
|
|
@@ -387,27 +434,38 @@ function ChatThread(_a) {
|
|
|
387
434
|
hasNewMessage: hasNewBelow
|
|
388
435
|
}
|
|
389
436
|
),
|
|
390
|
-
/* @__PURE__ */ jsx(
|
|
391
|
-
|
|
437
|
+
/* @__PURE__ */ jsx(
|
|
438
|
+
BottomSlot,
|
|
392
439
|
{
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
440
|
+
kind: isThinking ? onStopResponse ? "stop" : "hidden" : "messagebar",
|
|
441
|
+
messageBar: /* @__PURE__ */ jsx(
|
|
442
|
+
MessageBar,
|
|
443
|
+
{
|
|
444
|
+
state: messageBarState,
|
|
445
|
+
value: inputValue,
|
|
446
|
+
onChange: setInputValue,
|
|
447
|
+
onSendText: handleSendTextInternal,
|
|
448
|
+
onSendAudio: handleSendAudioInternal,
|
|
449
|
+
onStartRecording: handleStartRecordingInternal,
|
|
450
|
+
onPauseRecording: handlePauseRecordingInternal,
|
|
451
|
+
onResumeRecording: handleResumeRecordingInternal,
|
|
452
|
+
onCancelRecording: handleCancelRecordingInternal,
|
|
453
|
+
onTogglePlay,
|
|
454
|
+
onSeekPlayback,
|
|
455
|
+
recordingStream,
|
|
456
|
+
recordingDuration,
|
|
457
|
+
isPlaying,
|
|
458
|
+
playbackProgress,
|
|
459
|
+
placeholder,
|
|
460
|
+
maxRecordingDuration,
|
|
461
|
+
warnAtSecondsLeft,
|
|
462
|
+
secondsLeftLabel,
|
|
463
|
+
onMaxDurationReached: handleMaxDurationInternal
|
|
464
|
+
}
|
|
465
|
+
),
|
|
466
|
+
stopButton: /* @__PURE__ */ jsx(StopResponseButton, { onClick: onStopResponse, label: stopResponseText })
|
|
409
467
|
}
|
|
410
|
-
)
|
|
468
|
+
),
|
|
411
469
|
quotaExhausted && /* @__PURE__ */ jsx(AlertDialog, { open: true, children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
|
|
412
470
|
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
413
471
|
/* @__PURE__ */ jsx(AlertDialogTitle, { children: (quotaExhaustedConfig == null ? void 0 : quotaExhaustedConfig.title) || "Limite atingido" }),
|
|
@@ -424,5 +482,5 @@ function ChatThread(_a) {
|
|
|
424
482
|
}
|
|
425
483
|
|
|
426
484
|
export { ChatThread };
|
|
427
|
-
//# sourceMappingURL=chunk-
|
|
428
|
-
//# sourceMappingURL=chunk-
|
|
485
|
+
//# sourceMappingURL=chunk-JGUDRAWA.js.map
|
|
486
|
+
//# sourceMappingURL=chunk-JGUDRAWA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/composites/chat-thread.tsx"],"names":[],"mappings":"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","file":"chunk-JGUDRAWA.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronDown, Square } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ChatMessage } from \"@/components/ui/chat-message\"\nimport {\n MessageBar,\n type MessageBarState,\n} from \"@/components/ui/message-bar\"\nimport {\n MessageRating,\n DEFAULT_MESSAGE_RATING_LABELS,\n type MessageRatingValue,\n type MessageRatingLabels,\n type RatingLabel,\n} from \"@/components/ui/message-rating\"\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from \"@/components/ui/alert-dialog\"\n\n/* ─── Types ───────────────────────────────────────────────────── */\n\nexport type ChatThreadMessageStatus = \"sent\" | \"pending\" | \"failed\"\nexport type ChatThreadPersona = \"ai\" | \"user\" | \"system\"\n\nexport interface ChatThreadMessage {\n id: string\n persona: ChatThreadPersona\n status?: ChatThreadMessageStatus\n text?: string\n audioSrc?: string\n audioPeaks?: number[]\n /** Mensagem de erro pra exibir quando `persona=\"ai\"` e `status=\"failed\"` */\n errorText?: string\n /**\n * Quando true em uma mensagem da IA, renderiza o `MessageRating` (5 emojis) logo\n * abaixo da bubble — alinhado com a IA, parte da mesma \"linha visual\" da mensagem.\n * Apos o usuario responder, o rating some automaticamente (fade-out + slide-down).\n *\n * Usado quando a IA pede avaliacao da atividade: o consumer adiciona a msg da IA\n * com este campo `true` no array `messages` e ouve `onRate` para receber a resposta.\n */\n requestRating?: boolean\n}\n\nexport type ChatThreadState = \"idle\" | \"sending\" | \"thinking\" | \"error\"\n\nexport interface QuotaExhaustedConfig {\n title?: string\n description?: string\n ctaLabel?: string\n cancelLabel?: string\n onCta?: () => void\n onCancel?: () => void\n}\n\nexport interface ChatThreadProps extends Omit<React.ComponentProps<\"div\">, \"onChange\"> {\n /** Lista de mensagens da conversa */\n messages: ChatThreadMessage[]\n /** Estado global da conversa (controlled) */\n state?: ChatThreadState\n /** Quando true e thread vazio, monta direto em thinking (cenario Class — IA fala primeiro) */\n initialThinking?: boolean\n\n /* ─── Callbacks essenciais ─── */\n onSendText?: (text: string) => void\n /** Disparado quando user confirma envio do audio gravado (MessageBar dispara apos release/lock).\n * Consumer gerencia MediaRecorder e tem acesso ao Blob no momento que isso for chamado. */\n onSendAudio?: () => void\n /** Retry de mensagem do usuario que falhou enviar (B2) */\n onRetryMessage?: (messageId: string) => void\n /** Regenerar resposta da IA com erro (B3) */\n onRegenerateResponse?: () => void\n /** Cancelar resposta da IA mid-thinking (F1). Passar este callback **ativa** o botao\n * \"Parar resposta\" no rodape durante o estado `thinking`. Se omitido, o MessageBar\n * some com animacao de saida quando a IA esta pensando e volta com animacao de entrada\n * quando termina — o consumer indica que nao quer expor cancelamento. */\n onStopResponse?: () => void\n /** Carregar mensagens antigas (G1 — scroll infinito) */\n onLoadMore?: () => Promise<void> | void\n\n /* ─── Callbacks do MessageBar (pass-through) ─── */\n /** Dispara quando o user pressiona o mic. Consumer chama getUserMedia + MediaRecorder. */\n onStartRecording?: () => void\n /** Dispara quando o user pausa a gravacao. Consumer faz recorder.stop() + cria Blob. */\n onPauseRecording?: () => void\n /** Dispara quando o user retoma gravacao apos pause. */\n onResumeRecording?: () => void\n /** Dispara quando o user cancela a gravacao. Consumer cleanup do MediaRecorder. */\n onCancelRecording?: () => void\n /** Toggle play/pause do audio gravado durante o estado `paused` do MessageBar. */\n onTogglePlay?: () => void\n /** Callback de seek no waveform do audio gravado (durante paused). */\n onSeekPlayback?: (progress: number) => void\n\n /* ─── State do MessageBar (pass-through) ─── */\n /** Stream do microfone durante recording — usado pelo MessageBar pra renderizar o live waveform. */\n recordingStream?: MediaStream | null\n /** Duracao da gravacao em segundos (controlado pelo consumer via setInterval). */\n recordingDuration?: number\n /** Indica se o audio gravado esta tocando (durante paused). */\n isPlaying?: boolean\n /** Progresso de playback (0-1) — usado pra sincronizar dot verde no waveform. */\n playbackProgress?: number\n\n /* ─── Erro states (configuravel) ─── */\n /** Mostra banner de offline + disabled MessageBar (C1) */\n offline?: boolean\n /** Timestamp epoch ate quando bloquear envio (C2). null/undefined = sem rate limit */\n rateLimitedUntil?: number | null\n /** Texto do banner de rate limit. Default: \"Aguarde {s}s antes de enviar nova mensagem\" */\n rateLimitBannerText?: (secondsRemaining: number) => string\n /** Modal de cota esgotada (C3) */\n quotaExhausted?: boolean\n quotaExhaustedConfig?: QuotaExhaustedConfig\n\n /* ─── Rating (J) ─── */\n /**\n * Callback disparado quando o usuario responde um rating de uma mensagem com `requestRating=true`.\n * Recebe:\n * - `messageId`: id da mensagem da IA que pediu avaliacao\n * - `value`: numero 1-5\n * - `label`: objeto com emoji/title/subtitle correspondente ao value\n *\n * O consumer tipicamente usa esses dados para adicionar uma nova mensagem do usuario no array\n * `messages` com o texto da escolha (ex: `label.subtitle` em PT-BR). O `MessageRating` some\n * imediatamente apos o clique (sem estado \"selecionado\" visual).\n */\n onRate?: (messageId: string, value: MessageRatingValue, label: RatingLabel) => void\n /**\n * Labels customizadas do `MessageRating` (sobrescreve PT-BR defaults).\n * Passado pro componente E usado no callback `onRate` ao montar o `label`.\n */\n ratingLabels?: Partial<MessageRatingLabels>\n\n /* ─── Configuracoes do MessageBar ─── */\n placeholder?: string\n maxLength?: number\n /** Modo so audio — passa pro MessageBar como state base */\n audioOnlyMode?: boolean\n\n /* ─── Limite de duracao da gravacao de audio ─── */\n /**\n * Limite de duracao da gravacao em segundos (configurado pelo consumer).\n * Quando atingido, o ChatThread auto-pausa a gravacao (vai pro paused state com\n * preview play/cancel/send) — a menos que `onMaxDurationReached` seja passado,\n * caso em que o consumer assume controle. Sem essa prop, sem limite.\n */\n maxRecordingDuration?: number\n /** Quantos segundos antes do limite ativar o warning visual (timer destructive\n * + label \"Xs restantes\"). Default 10. Ignorado sem `maxRecordingDuration`. */\n warnAtSecondsLeft?: number\n /** Label do warning. Default pt-BR: `(s) => \\`${s}s restantes\\``. */\n secondsLeftLabel?: (secondsLeft: number) => string\n /**\n * Callback opcional disparado ao atingir o limite. Se omitido, ChatThread\n * auto-pausa internamente. Se passado, **substitui** o auto-pause — o consumer\n * decide o que fazer (ex: mostrar toast antes de pausar manualmente).\n */\n onMaxDurationReached?: () => void\n\n /* ─── Identidade do usuario ─── */\n /** URL da imagem do avatar do usuario (aparece em todas as msgs do user no desktop). */\n userAvatar?: string\n /** Nome do usuario (usado para iniciais no fallback do avatar e alt da imagem). */\n userName?: string\n\n /* ─── i18n / texto customizavel ─── */\n /** Default: \"Sem conexao. Tentando reconectar...\" */\n offlineBannerText?: string\n /** Default: \"Tentar novamente\" */\n retryButtonText?: string\n /** Default: \"Regenerar resposta\" */\n regenerateButtonText?: string\n /** Default: \"Parar resposta\" */\n stopResponseText?: string\n /** Default: \"Desculpe, nao consegui responder.\" */\n defaultAiErrorText?: string\n}\n\n/* ─── Constantes ──────────────────────────────────────────────── */\n\nconst SCROLL_BOTTOM_THRESHOLD = 100 // px do bottom pra considerar \"no fundo\"\nconst LOAD_MORE_THRESHOLD = 200 // px do topo pra disparar onLoadMore\n\n/* ─── Sub-componentes internos ────────────────────────────────── */\n\n/** Banner persistente no topo (offline, rate limit, etc.) */\nfunction ChatThreadBanner({\n variant,\n children,\n}: {\n variant: \"offline\" | \"rate-limit\"\n children: React.ReactNode\n}) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"shrink-0 flex items-center gap-2 px-4 py-2 text-sm border-b\",\n variant === \"offline\" &&\n \"bg-destructive/10 text-destructive border-destructive/20\",\n variant === \"rate-limit\" &&\n \"bg-muted text-muted-foreground border-border\"\n )}\n >\n {children}\n </div>\n )\n}\n\n/** Conta segundos restantes ate `until` (timestamp epoch). */\nfunction useCountdown(until: number | null | undefined): number {\n const [now, setNow] = React.useState(() => Date.now())\n\n React.useEffect(() => {\n if (!until || until <= Date.now()) return\n const id = setInterval(() => setNow(Date.now()), 1000)\n return () => clearInterval(id)\n }, [until])\n\n if (!until) return 0\n const remainingMs = until - now\n return Math.max(0, Math.ceil(remainingMs / 1000))\n}\n\n/** Botao \"Parar resposta\" — substitui MessageBar durante thinking (F1) */\nfunction StopResponseButton({\n onClick,\n label = \"Parar resposta\",\n}: {\n onClick?: () => void\n label?: string\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"w-full flex items-center justify-center gap-2 h-12 rounded-2xl bg-muted text-neutral-foreground hover:bg-muted/80 transition-colors focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n aria-label={label}\n >\n <Square className=\"size-4\" fill=\"currentColor\" strokeWidth={0} />\n <span className=\"text-sm font-medium\">{label}</span>\n </button>\n )\n}\n\n/** Botao flutuante \"↓ Nova mensagem\" — aparece quando ha msg fora do viewport */\nfunction ScrollToBottomButton({\n onClick,\n hasNewMessage,\n}: {\n onClick?: () => void\n hasNewMessage: boolean\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"absolute bottom-2 left-1/2 -translate-x-1/2 z-10 inline-flex items-center justify-center size-10 rounded-full bg-background border border-border shadow-md hover:bg-muted/50 transition-all focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n aria-label={hasNewMessage ? \"Nova mensagem — ir para o fim\" : \"Ir para o fim\"}\n >\n <ChevronDown className=\"size-5 text-neutral-foreground\" />\n {hasNewMessage && (\n <span\n className=\"absolute top-1 right-1 size-2 rounded-full bg-primary theme-brand\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n )\n}\n\n/** Bubble wrapper com animacao de entrada (E1: fade-in + slide-up 8px, 200ms) */\nfunction MessageBubbleAnimated({\n children,\n enableAnimation,\n}: {\n children: React.ReactNode\n enableAnimation: boolean\n}) {\n return (\n <div\n className={cn(\n \"transition-[opacity,transform] duration-200 ease-out\",\n enableAnimation ? \"animate-thread-msg-enter\" : \"\"\n )}\n >\n {children}\n </div>\n )\n}\n\n/* ─── Bottom slot: gerencia animacao sequencial entre MessageBar / StopButton / hidden ─── */\n\ntype BottomSlotKind = \"messagebar\" | \"stop\" | \"hidden\"\nconst LEAVE_DURATION_MS = 150\n\n/**\n * Slot que alterna entre 3 estados com animacao sequencial (sem cross-fade):\n * o conteudo atual anima saida (`thread-msg-leave`, 150ms), troca o conteudo,\n * e o novo anima entrada (`thread-msg-enter`, 200ms). Similar ao\n * AnimatePresence mode=\"wait\" do Framer Motion, mas em CSS puro.\n */\nfunction BottomSlot({\n kind,\n messageBar,\n stopButton,\n}: {\n kind: BottomSlotKind\n messageBar: React.ReactNode\n stopButton: React.ReactNode\n}) {\n const [rendered, setRendered] = React.useState<BottomSlotKind>(kind)\n const [phase, setPhase] = React.useState<\"enter\" | \"leave\">(\"enter\")\n\n React.useEffect(() => {\n if (rendered === kind) return\n setPhase(\"leave\")\n const t = setTimeout(() => {\n setRendered(kind)\n setPhase(\"enter\")\n }, LEAVE_DURATION_MS)\n return () => clearTimeout(t)\n }, [kind, rendered])\n\n return (\n <div className=\"shrink-0 px-4 pb-4 pt-2\">\n {rendered !== \"hidden\" && (\n <div\n key={rendered}\n className={\n phase === \"enter\" ? \"animate-thread-msg-enter\" : \"animate-thread-msg-leave\"\n }\n >\n {rendered === \"messagebar\" ? messageBar : stopButton}\n </div>\n )}\n </div>\n )\n}\n\n/* ─── Component principal ─────────────────────────────────────── */\n\nfunction ChatThread({\n messages,\n state = \"idle\",\n initialThinking = false,\n onSendText,\n onSendAudio,\n onRetryMessage,\n onRegenerateResponse,\n onStopResponse,\n onLoadMore,\n onStartRecording,\n onPauseRecording,\n onResumeRecording,\n onCancelRecording,\n onTogglePlay,\n onSeekPlayback,\n recordingStream,\n recordingDuration,\n isPlaying,\n playbackProgress,\n offline = false,\n rateLimitedUntil = null,\n rateLimitBannerText,\n quotaExhausted = false,\n quotaExhaustedConfig,\n onRate,\n ratingLabels,\n placeholder,\n maxLength,\n audioOnlyMode = false,\n maxRecordingDuration,\n warnAtSecondsLeft,\n secondsLeftLabel,\n onMaxDurationReached,\n userAvatar,\n userName,\n offlineBannerText = \"Sem conexao. Tentando reconectar...\",\n retryButtonText = \"Tentar novamente\",\n regenerateButtonText = \"Regenerar resposta\",\n stopResponseText = \"Parar resposta\",\n defaultAiErrorText = \"Desculpe, nao consegui responder.\",\n className,\n ...props\n}: ChatThreadProps) {\n /* ─── State derivado ─── */\n const rateLimitSecondsLeft = useCountdown(rateLimitedUntil)\n const isRateLimited = rateLimitSecondsLeft > 0\n const isThinking =\n state === \"thinking\" || (initialThinking && messages.length === 0)\n const isDisabled = offline || isRateLimited || quotaExhausted\n\n /* ─── Refs e scroll inteligente (D1) ─── */\n const scrollRef = React.useRef<HTMLDivElement>(null)\n const [isAtBottom, setIsAtBottom] = React.useState(true)\n const [hasNewBelow, setHasNewBelow] = React.useState(false)\n const prevMessageCountRef = React.useRef(messages.length)\n const loadMoreInFlightRef = React.useRef(false)\n const [isLoadingMore, setIsLoadingMore] = React.useState(false)\n // Marca de quando o componente montou — usada para suprimir animacao das mensagens iniciais\n const mountedRef = React.useRef(false)\n React.useEffect(() => {\n mountedRef.current = true\n }, [])\n\n const checkScrollPosition = React.useCallback(() => {\n const el = scrollRef.current\n if (!el) return\n const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight\n const atBottom = distanceFromBottom <= SCROLL_BOTTOM_THRESHOLD\n setIsAtBottom(atBottom)\n if (atBottom) setHasNewBelow(false)\n }, [])\n\n const scrollToBottom = React.useCallback((smooth = true) => {\n const el = scrollRef.current\n if (!el) return\n el.scrollTo({\n top: el.scrollHeight,\n behavior: smooth ? \"smooth\" : \"auto\",\n })\n setHasNewBelow(false)\n }, [])\n\n /* ─── Auto-scroll quando chega nova mensagem ─── */\n React.useEffect(() => {\n const prev = prevMessageCountRef.current\n const curr = messages.length\n prevMessageCountRef.current = curr\n\n if (curr <= prev) return\n\n if (isAtBottom) {\n // Esta no fundo → scroll suave pra nova msg\n requestAnimationFrame(() => scrollToBottom(true))\n } else {\n // Usuario subiu → mostra botao\n setHasNewBelow(true)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [messages.length])\n\n /* ─── Scroll handler (detecta posicao + paginacao) ─── */\n React.useEffect(() => {\n const el = scrollRef.current\n if (!el) return\n const handler = () => {\n checkScrollPosition()\n // Paginacao: se chegou perto do topo e ha onLoadMore, dispara\n if (\n onLoadMore &&\n !loadMoreInFlightRef.current &&\n el.scrollTop <= LOAD_MORE_THRESHOLD\n ) {\n loadMoreInFlightRef.current = true\n setIsLoadingMore(true)\n const prevScrollHeight = el.scrollHeight\n Promise.resolve(onLoadMore())\n .then(() => {\n // Preserva posicao visual apos prepend de mensagens antigas\n requestAnimationFrame(() => {\n const newScrollHeight = el.scrollHeight\n el.scrollTop = newScrollHeight - prevScrollHeight\n })\n })\n .finally(() => {\n loadMoreInFlightRef.current = false\n setIsLoadingMore(false)\n })\n }\n }\n el.addEventListener(\"scroll\", handler, { passive: true })\n // Inicial: garante scroll no fundo\n requestAnimationFrame(() => scrollToBottom(false))\n return () => el.removeEventListener(\"scroll\", handler)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [onLoadMore])\n\n /* ─── Aria-live announce de nova msg da IA (H1) ─── */\n const lastAiMessage = React.useMemo(() => {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].persona === \"ai\") return messages[i]\n }\n return null\n }, [messages])\n\n /* ─── Rating per-message: rastreia IDs cujo rating foi respondido (auto-dismiss imediato) ─── */\n const [ratedMessageIds, setRatedMessageIds] = React.useState<Set<string>>(() => new Set())\n\n // Merge dos labels customizados com defaults PT-BR. Usado pra renderizar E pra montar o callback.\n const mergedRatingLabels: MessageRatingLabels = React.useMemo(\n () => ({ ...DEFAULT_MESSAGE_RATING_LABELS, ...ratingLabels }),\n [ratingLabels]\n )\n\n const handleRateMessage = React.useCallback(\n (messageId: string, value: MessageRatingValue) => {\n // Marca como respondido IMEDIATAMENTE — re-render remove o rating do DOM antes\n // do paint visual de \"selected\", entao o usuario nao ve o estado intermediario.\n setRatedMessageIds((prev) => {\n const next = new Set(prev)\n next.add(messageId)\n return next\n })\n // Dispara callback com label completo (emoji/title/subtitle).\n onRate?.(messageId, value, mergedRatingLabels[value])\n },\n [onRate, mergedRatingLabels]\n )\n\n /* ─── MessageBar state interno (state machine de gravacao) ─── */\n const baseMessageBarState: MessageBarState = audioOnlyMode ? \"audio-only\" : \"default\"\n const [internalRecordingState, setInternalRecordingState] = React.useState<\n \"idle\" | \"recording\" | \"paused\"\n >(\"idle\")\n\n // Reset pra idle quando muda audioOnlyMode e nao esta gravando\n React.useEffect(() => {\n if (internalRecordingState === \"idle\") return\n // mantem o state se gravacao em andamento\n }, [audioOnlyMode, internalRecordingState])\n\n // State final do MessageBar — combina base, recording state e disabled\n const messageBarState: MessageBarState = isDisabled\n ? \"disabled\"\n : internalRecordingState === \"recording\"\n ? \"recording\"\n : internalRecordingState === \"paused\"\n ? \"paused\"\n : baseMessageBarState\n\n /* Wrappers dos callbacks: atualizam state interno + chamam consumer */\n const handleStartRecordingInternal = React.useCallback(() => {\n setInternalRecordingState(\"recording\")\n onStartRecording?.()\n }, [onStartRecording])\n\n const handlePauseRecordingInternal = React.useCallback(() => {\n setInternalRecordingState(\"paused\")\n onPauseRecording?.()\n }, [onPauseRecording])\n\n const handleResumeRecordingInternal = React.useCallback(() => {\n setInternalRecordingState(\"recording\")\n onResumeRecording?.()\n }, [onResumeRecording])\n\n const handleCancelRecordingInternal = React.useCallback(() => {\n setInternalRecordingState(\"idle\")\n onCancelRecording?.()\n }, [onCancelRecording])\n\n const handleSendAudioInternal = React.useCallback(() => {\n setInternalRecordingState(\"idle\")\n onSendAudio?.()\n }, [onSendAudio])\n\n /* Auto-pause ao atingir limite de duracao. Se consumer passou onMaxDurationReached,\n delega controle pra ele (sem auto-pause). */\n const handleMaxDurationInternal = React.useCallback(() => {\n if (onMaxDurationReached) {\n onMaxDurationReached()\n } else {\n handlePauseRecordingInternal()\n }\n }, [onMaxDurationReached, handlePauseRecordingInternal])\n\n /* Input controlled — sem isso o MessageBar fica \"engessado\" em value=\"\"\n (o consumer recebe o texto via onSendText, mas nao precisa controlar o input). */\n const [inputValue, setInputValue] = React.useState(\"\")\n const handleSendTextInternal = React.useCallback(\n (text: string) => {\n setInputValue(\"\")\n onSendText?.(text)\n },\n [onSendText]\n )\n\n /* ─── Render ──────────────────────────────────────── */\n return (\n <div\n data-slot=\"chat-thread\"\n className={cn(\"relative flex flex-col h-full bg-background\", className)}\n {...props}\n >\n {/* Banners de erro (topo) */}\n {offline && (\n <ChatThreadBanner variant=\"offline\">\n <span aria-hidden=\"true\">⚠</span>\n <span>{offlineBannerText}</span>\n </ChatThreadBanner>\n )}\n {isRateLimited && (\n <ChatThreadBanner variant=\"rate-limit\">\n <span aria-hidden=\"true\">⏱</span>\n <span>\n {rateLimitBannerText\n ? rateLimitBannerText(rateLimitSecondsLeft)\n : `Aguarde ${rateLimitSecondsLeft}s antes de enviar nova mensagem`}\n </span>\n </ChatThreadBanner>\n )}\n\n {/* Thread scrollavel */}\n <div\n ref={scrollRef}\n className=\"flex-1 overflow-y-auto px-4 py-4 space-y-4\"\n role=\"log\"\n aria-live=\"polite\"\n aria-atomic=\"false\"\n >\n {/* Spinner de paginacao no topo (G2) */}\n {isLoadingMore && (\n <div className=\"flex justify-center py-2\" aria-label=\"Carregando mensagens anteriores\">\n <span className=\"inline-block size-5 border-2 border-muted-foreground/30 border-t-muted-foreground rounded-full animate-spin\" />\n </div>\n )}\n\n {messages.map((msg, idx) => {\n // Suprime animacao das mensagens que ja existiam no mount inicial\n const enableAnim =\n mountedRef.current && idx >= prevMessageCountRef.current - 1\n\n const isFailedUser = msg.persona === \"user\" && msg.status === \"failed\"\n const isFailedAi = msg.persona === \"ai\" && msg.status === \"failed\"\n const isPendingUser = msg.persona === \"user\" && msg.status === \"pending\"\n\n return (\n <MessageBubbleAnimated key={msg.id} enableAnimation={enableAnim}>\n <ChatMessage\n persona={msg.persona}\n text={msg.text}\n audioSrc={msg.audioSrc}\n avatar={msg.persona === \"user\" ? userAvatar : undefined}\n author={msg.persona === \"user\" ? userName : undefined}\n // Indicador de pending: typing dots no lugar do conteudo normal e visual sutil\n loading={isPendingUser && !msg.text && !msg.audioSrc}\n className={cn(\n isPendingUser && \"opacity-80\",\n isFailedUser && \"[&_[data-slot=chat-message-bubble]]:border-2 [&_[data-slot=chat-message-bubble]]:border-destructive\"\n )}\n />\n {/* Retry inline pra msg do user que falhou (B2) */}\n {isFailedUser && (\n <div className=\"mt-2 flex justify-end\">\n <button\n type=\"button\"\n onClick={() => onRetryMessage?.(msg.id)}\n className=\"inline-flex items-center gap-1 text-xs text-destructive hover:underline focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 rounded\"\n >\n ↻ {retryButtonText}\n </button>\n </div>\n )}\n {/* Bubble de erro pra resposta da IA (B3) */}\n {isFailedAi && (\n /* Alinhado com a bubble da IA: offset = badge 32px + gap 12px = 44px (desktop).\n Mobile sem offset porque o badge fica oculto no ChatMessage AI. */\n <div className=\"mt-2 sm:pl-11 flex flex-col items-start gap-2\">\n <div className=\"text-sm text-destructive\">\n {msg.errorText || defaultAiErrorText}\n </div>\n <button\n type=\"button\"\n onClick={onRegenerateResponse}\n className=\"inline-flex items-center gap-1 text-xs text-primary hover:underline focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 rounded\"\n >\n ↻ {regenerateButtonText}\n </button>\n </div>\n )}\n {/* MessageRating inline na mensagem da IA que pede avaliacao (J).\n Alinhado com a bubble da IA (offset 44px desktop, 0 mobile).\n value={null} mantem o componente sem estado \"selecionado\" visual —\n ao clicar, o ChatThread marca como rated imediatamente (re-render remove\n do DOM antes do paint), e o consumer recebe (messageId, value, label). */}\n {msg.persona === \"ai\" && msg.requestRating && !ratedMessageIds.has(msg.id) && (\n <div className=\"mt-3 sm:pl-11 animate-thread-msg-enter\">\n <MessageRating\n value={null}\n labels={ratingLabels}\n onChange={(value) => handleRateMessage(msg.id, value)}\n />\n </div>\n )}\n </MessageBubbleAnimated>\n )\n })}\n\n {/* Typing indicator da IA durante thinking */}\n {isThinking && (\n <MessageBubbleAnimated enableAnimation>\n <ChatMessage persona=\"ai\" loading />\n </MessageBubbleAnimated>\n )}\n\n {/* Aria-live oculto pra anunciar ultima msg da IA */}\n <div className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {lastAiMessage?.text || \"\"}\n </div>\n </div>\n\n {/* Scroll-to-bottom button (D1) */}\n {!isAtBottom && (\n <ScrollToBottomButton\n onClick={() => scrollToBottom(true)}\n hasNewMessage={hasNewBelow}\n />\n )}\n\n {/* Bottom area: MessageBar / StopResponse / hidden.\n O botao \"Parar resposta\" so aparece durante thinking E quando o consumer passa\n `onStopResponse` — quem nao implementa cancelamento ve o MessageBar sumir com\n animacao de saida e voltar com animacao de entrada quando a IA termina. */}\n <BottomSlot\n kind={\n isThinking\n ? onStopResponse\n ? \"stop\"\n : \"hidden\"\n : \"messagebar\"\n }\n messageBar={\n <MessageBar\n state={messageBarState}\n value={inputValue}\n onChange={setInputValue}\n onSendText={handleSendTextInternal}\n onSendAudio={handleSendAudioInternal}\n onStartRecording={handleStartRecordingInternal}\n onPauseRecording={handlePauseRecordingInternal}\n onResumeRecording={handleResumeRecordingInternal}\n onCancelRecording={handleCancelRecordingInternal}\n onTogglePlay={onTogglePlay}\n onSeekPlayback={onSeekPlayback}\n recordingStream={recordingStream}\n recordingDuration={recordingDuration}\n isPlaying={isPlaying}\n playbackProgress={playbackProgress}\n placeholder={placeholder}\n maxRecordingDuration={maxRecordingDuration}\n warnAtSecondsLeft={warnAtSecondsLeft}\n secondsLeftLabel={secondsLeftLabel}\n onMaxDurationReached={handleMaxDurationInternal}\n />\n }\n stopButton={\n <StopResponseButton onClick={onStopResponse} label={stopResponseText} />\n }\n />\n\n {/* Quota exhausted modal (C3) */}\n {quotaExhausted && (\n <AlertDialog open>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n {quotaExhaustedConfig?.title || \"Limite atingido\"}\n </AlertDialogTitle>\n <AlertDialogDescription>\n {quotaExhaustedConfig?.description ||\n \"Voce atingiu o limite de mensagens do seu plano. Faca upgrade para continuar.\"}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n {quotaExhaustedConfig?.onCancel && (\n <AlertDialogCancel onClick={quotaExhaustedConfig.onCancel}>\n {quotaExhaustedConfig.cancelLabel || \"Cancelar\"}\n </AlertDialogCancel>\n )}\n <AlertDialogAction onClick={quotaExhaustedConfig?.onCta}>\n {quotaExhaustedConfig?.ctaLabel || \"Fazer upgrade\"}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n </div>\n )\n}\n\nexport { ChatThread }\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
function useReducedMotion() {
|
|
4
|
+
const [reduced, setReduced] = useState(false);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
7
|
+
setReduced(media.matches);
|
|
8
|
+
const handler = (event) => setReduced(event.matches);
|
|
9
|
+
media.addEventListener("change", handler);
|
|
10
|
+
return () => media.removeEventListener("change", handler);
|
|
11
|
+
}, []);
|
|
12
|
+
return reduced;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { useReducedMotion };
|
|
16
|
+
//# sourceMappingURL=chunk-K2NUBNSA.js.map
|
|
17
|
+
//# sourceMappingURL=chunk-K2NUBNSA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-reduced-motion.ts"],"names":[],"mappings":";;AAYO,SAAS,gBAAA,GAA4B;AAC1C,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAE5C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,UAAA,CAAW,kCAAkC,CAAA;AAClE,IAAA,UAAA,CAAW,MAAM,OAAO,CAAA;AAExB,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAA+B,UAAA,CAAW,MAAM,OAAO,CAAA;AACxE,IAAA,KAAA,CAAM,gBAAA,CAAiB,UAAU,OAAO,CAAA;AACxC,IAAA,OAAO,MAAM,KAAA,CAAM,mBAAA,CAAoB,QAAA,EAAU,OAAO,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,OAAA;AACT","file":"chunk-K2NUBNSA.js","sourcesContent":["\"use client\"\n\nimport { useEffect, useState } from \"react\"\n\n/**\n * Returns `true` quando o usuario habilitou \"prefers-reduced-motion\" no SO.\n * Componentes do `marketing/motion/*` consultam esse hook pra desligar animacoes\n * (resolver para o estado final direto) — requisito WCAG 2.3.3.\n *\n * SSR-safe: comeca em `false` no server e atualiza no client apos mount.\n * Reage a mudancas dinamicas (usuario toggla a preferencia com a aba aberta).\n */\nexport function useReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false)\n\n useEffect(() => {\n const media = window.matchMedia(\"(prefers-reduced-motion: reduce)\")\n setReduced(media.matches)\n\n const handler = (event: MediaQueryListEvent) => setReduced(event.matches)\n media.addEventListener(\"change\", handler)\n return () => media.removeEventListener(\"change\", handler)\n }, [])\n\n return reduced\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
function SmoothAnchor({ headerOffset = 96, duration = 900 }) {
|
|
4
|
+
React.useEffect(() => {
|
|
5
|
+
if (typeof window === "undefined") return;
|
|
6
|
+
if (window.location.hash) {
|
|
7
|
+
const id = window.location.hash.slice(1);
|
|
8
|
+
const el = document.getElementById(id);
|
|
9
|
+
if (el) {
|
|
10
|
+
requestAnimationFrame(() => el.classList.add("anchor-target-pulse"));
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function onClick(e) {
|
|
14
|
+
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey) return;
|
|
15
|
+
const target = e.target;
|
|
16
|
+
const anchor = target == null ? void 0 : target.closest('a[href^="#"]');
|
|
17
|
+
if (!anchor) return;
|
|
18
|
+
const href = anchor.getAttribute("href");
|
|
19
|
+
if (!href || href === "#") return;
|
|
20
|
+
const id = href.slice(1);
|
|
21
|
+
const el = document.getElementById(id);
|
|
22
|
+
if (!el) return;
|
|
23
|
+
e.preventDefault();
|
|
24
|
+
const prefersReduced = window.matchMedia(
|
|
25
|
+
"(prefers-reduced-motion: reduce)"
|
|
26
|
+
).matches;
|
|
27
|
+
const rect = el.getBoundingClientRect();
|
|
28
|
+
const targetY = window.scrollY + rect.top - headerOffset;
|
|
29
|
+
if (prefersReduced) {
|
|
30
|
+
window.scrollTo(0, targetY);
|
|
31
|
+
} else {
|
|
32
|
+
smoothScrollTo(targetY, duration);
|
|
33
|
+
}
|
|
34
|
+
history.replaceState(null, "", href);
|
|
35
|
+
el.classList.remove("anchor-target-pulse");
|
|
36
|
+
void el.offsetWidth;
|
|
37
|
+
el.classList.add("anchor-target-pulse");
|
|
38
|
+
}
|
|
39
|
+
document.addEventListener("click", onClick);
|
|
40
|
+
return () => document.removeEventListener("click", onClick);
|
|
41
|
+
}, [headerOffset, duration]);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function smoothScrollTo(targetY, duration) {
|
|
45
|
+
const startY = window.scrollY;
|
|
46
|
+
const distance = targetY - startY;
|
|
47
|
+
if (Math.abs(distance) < 2) return;
|
|
48
|
+
const startTime = performance.now();
|
|
49
|
+
function step(now) {
|
|
50
|
+
const elapsed = now - startTime;
|
|
51
|
+
const t = Math.min(elapsed / duration, 1);
|
|
52
|
+
const eased = easeInOutCubic(t);
|
|
53
|
+
window.scrollTo(0, startY + distance * eased);
|
|
54
|
+
if (t < 1) requestAnimationFrame(step);
|
|
55
|
+
}
|
|
56
|
+
requestAnimationFrame(step);
|
|
57
|
+
}
|
|
58
|
+
function easeInOutCubic(t) {
|
|
59
|
+
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { SmoothAnchor };
|
|
63
|
+
//# sourceMappingURL=chunk-NW56QDQM.js.map
|
|
64
|
+
//# sourceMappingURL=chunk-NW56QDQM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/motion/smooth-anchor.tsx"],"names":[],"mappings":"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","file":"chunk-NW56QDQM.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nexport interface SmoothAnchorProps {\n /** Offset em px pra compensar header sticky. Default `96`. */\n headerOffset?: number\n /** Duracao do scroll em ms. Default `900`. */\n duration?: number\n}\n\n/**\n * Intercepta cliques em links de hash (`<a href=\"#algo\">`) e faz scroll suave\n * com easing `easeInOutCubic` em vez do `scroll-behavior: smooth` nativo\n * (que tem duracao curta e easing fixo).\n *\n * Renderiza `null` (so registra listener global). Monte UMA VEZ por app,\n * tipicamente no `<RootLayout>` ou na pagina raiz da landing.\n *\n * Comportamento:\n * - Ignora clicks com modificadores (cmd/ctrl/middle-button).\n * - Atualiza URL via `history.replaceState` sem disparar scroll nativo.\n * - Adiciona classe `anchor-target-pulse` no destino apos chegar (animacao\n * visual opcional, definida em `globals.css`).\n * - Respeita `prefers-reduced-motion` (scroll instantaneo, sem easing).\n *\n * @example\n * // app/layout.tsx\n * <body>\n * <SmoothAnchor headerOffset={64} />\n * {children}\n * </body>\n */\nfunction SmoothAnchor({ headerOffset = 96, duration = 900 }: SmoothAnchorProps) {\n React.useEffect(() => {\n if (typeof window === \"undefined\") return\n\n // Se a pagina abre ja com hash, pulsa o destino apos o scroll inicial.\n if (window.location.hash) {\n const id = window.location.hash.slice(1)\n const el = document.getElementById(id)\n if (el) {\n requestAnimationFrame(() => el.classList.add(\"anchor-target-pulse\"))\n }\n }\n\n function onClick(e: MouseEvent) {\n if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey) return\n const target = e.target as HTMLElement | null\n const anchor = target?.closest('a[href^=\"#\"]') as HTMLAnchorElement | null\n if (!anchor) return\n const href = anchor.getAttribute(\"href\")\n if (!href || href === \"#\") return\n const id = href.slice(1)\n const el = document.getElementById(id)\n if (!el) return\n\n e.preventDefault()\n const prefersReduced = window.matchMedia(\n \"(prefers-reduced-motion: reduce)\"\n ).matches\n\n const rect = el.getBoundingClientRect()\n const targetY = window.scrollY + rect.top - headerOffset\n\n if (prefersReduced) {\n window.scrollTo(0, targetY)\n } else {\n smoothScrollTo(targetY, duration)\n }\n\n history.replaceState(null, \"\", href)\n // Reativa pulse mesmo se a URL ja for a mesma\n el.classList.remove(\"anchor-target-pulse\")\n void el.offsetWidth\n el.classList.add(\"anchor-target-pulse\")\n }\n\n document.addEventListener(\"click\", onClick)\n return () => document.removeEventListener(\"click\", onClick)\n }, [headerOffset, duration])\n\n return null\n}\n\nfunction smoothScrollTo(targetY: number, duration: number) {\n const startY = window.scrollY\n const distance = targetY - startY\n if (Math.abs(distance) < 2) return\n const startTime = performance.now()\n\n function step(now: number) {\n const elapsed = now - startTime\n const t = Math.min(elapsed / duration, 1)\n const eased = easeInOutCubic(t)\n window.scrollTo(0, startY + distance * eased)\n if (t < 1) requestAnimationFrame(step)\n }\n\n requestAnimationFrame(step)\n}\n\nfunction easeInOutCubic(t: number): number {\n return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2\n}\n\nexport { SmoothAnchor }\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { cn } from './chunk-TYCPXAXF.js';
|
|
2
|
+
import { __objRest, __spreadValues } from './chunk-YINJ5YZ5.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var Section = React.forwardRef(function Section2(_a, ref) {
|
|
7
|
+
var _b = _a, { as = "section", variant = "default", tone = "dark", id, className } = _b, props = __objRest(_b, ["as", "variant", "tone", "id", "className"]);
|
|
8
|
+
const Tag = as;
|
|
9
|
+
return /* @__PURE__ */ jsx(
|
|
10
|
+
Tag,
|
|
11
|
+
__spreadValues({
|
|
12
|
+
ref,
|
|
13
|
+
id,
|
|
14
|
+
"data-slot": "marketing-section",
|
|
15
|
+
"data-variant": variant,
|
|
16
|
+
"data-tone": tone,
|
|
17
|
+
className: cn(
|
|
18
|
+
// base
|
|
19
|
+
"relative w-full",
|
|
20
|
+
// variants
|
|
21
|
+
variant === "hero" && "min-h-screen flex flex-col scroll-mt-0",
|
|
22
|
+
variant === "default" && "py-20 md:py-28 scroll-mt-8",
|
|
23
|
+
// tone
|
|
24
|
+
tone === "light" && "light-surface",
|
|
25
|
+
className
|
|
26
|
+
)
|
|
27
|
+
}, props)
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export { Section };
|
|
32
|
+
//# sourceMappingURL=chunk-NZXP7BAH.js.map
|
|
33
|
+
//# sourceMappingURL=chunk-NZXP7BAH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/layout/section.tsx"],"names":["Section"],"mappings":";;;;;AAoCA,IAAM,OAAA,GAAgB,KAAA,CAAA,UAAA,CAAsC,SAASA,QAAAA,CACnE,IACA,GAAA,EACA;AAFA,EAAA,IAAA,EAAA,GAAA,EAAA,EAAE,OAAK,SAAA,EAAW,OAAA,GAAU,SAAA,EAAW,IAAA,GAAO,QAAQ,EAAA,EAAI,SAAA,EArC5D,GAqCE,EAAA,EAAwE,kBAAxE,EAAA,EAAwE,CAAtE,IAAA,EAAgB,SAAA,EAAqB,QAAe,IAAA,EAAI,WAAA,CAAA,CAAA;AAG1D,EAAA,MAAM,GAAA,GAAM,EAAA;AACZ,EAAA,uBACE,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA,cAAA,CAAA;AAAA,MACC,GAAA;AAAA,MACA,EAAA;AAAA,MACA,WAAA,EAAU,mBAAA;AAAA,MACV,cAAA,EAAc,OAAA;AAAA,MACd,WAAA,EAAW,IAAA;AAAA,MACX,SAAA,EAAW,EAAA;AAAA;AAAA,QAET,iBAAA;AAAA;AAAA,QAEA,YAAY,MAAA,IAAU,wCAAA;AAAA,QACtB,YAAY,SAAA,IAAa,4BAAA;AAAA;AAAA,QAEzB,SAAS,OAAA,IAAW,eAAA;AAAA,QACpB;AAAA;AACF,KAAA,EACI,KAAA;AAAA,GACN;AAEJ,CAAC","file":"chunk-NZXP7BAH.js","sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface SectionProps extends React.HTMLAttributes<HTMLElement> {\n /** Tag HTML renderizada. Default `\"section\"`. */\n as?: \"section\" | \"div\"\n /**\n * Forma da dobra:\n * - `\"hero\"`: `min-h-screen flex flex-col` (primeira dobra acima do fold).\n * - `\"default\"`: padding vertical generoso (`py-20 md:py-28`) — usado nas demais.\n */\n variant?: \"hero\" | \"default\"\n /**\n * Aplica `.light-surface` quando `\"light\"` — sobrescreve os tokens semanticos\n * pra um fundo claro dentro de tema dark global. `\"dark\"` nao aplica nada\n * (segue o tema do root).\n */\n tone?: \"dark\" | \"light\"\n}\n\n/**\n * Wrapper de uma \"dobra\" de landing page. Generaliza o `HomeSection` do\n * `fluencypass-corporate-site`: padroniza padding/altura via `variant` e\n * permite alternar bg dark/light por dobra via `tone`.\n *\n * Pareie com `SectionHeading`, `SectionEyebrow`, `SectionSubtitle` pra montar\n * o cabecalho da dobra com tipografia consistente.\n *\n * @example\n * <Section id=\"pilares\" variant=\"default\" tone=\"light\">\n * <SectionEyebrow>O que oferecemos</SectionEyebrow>\n * <SectionHeading>3 pilares essenciais</SectionHeading>\n * <div className=\"grid md:grid-cols-3 gap-6\">...</div>\n * </Section>\n */\nconst Section = React.forwardRef<HTMLElement, SectionProps>(function Section(\n { as = \"section\", variant = \"default\", tone = \"dark\", id, className, ...props },\n ref\n) {\n const Tag = as as React.ElementType\n return (\n <Tag\n ref={ref}\n id={id}\n data-slot=\"marketing-section\"\n data-variant={variant}\n data-tone={tone}\n className={cn(\n // base\n \"relative w-full\",\n // variants\n variant === \"hero\" && \"min-h-screen flex flex-col scroll-mt-0\",\n variant === \"default\" && \"py-20 md:py-28 scroll-mt-8\",\n // tone\n tone === \"light\" && \"light-surface\",\n className\n )}\n {...props}\n />\n )\n})\n\nexport { Section }\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useReducedMotion } from './chunk-K2NUBNSA.js';
|
|
2
|
+
import { useIntersection } from './chunk-XQUQDZVA.js';
|
|
3
|
+
import { cn } from './chunk-TYCPXAXF.js';
|
|
4
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-YINJ5YZ5.js';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function StaggerReveal(_a) {
|
|
9
|
+
var _b = _a, {
|
|
10
|
+
step = 100,
|
|
11
|
+
threshold = 0.15,
|
|
12
|
+
rootMargin = "0px 0px -10% 0px",
|
|
13
|
+
className,
|
|
14
|
+
children
|
|
15
|
+
} = _b, props = __objRest(_b, [
|
|
16
|
+
"step",
|
|
17
|
+
"threshold",
|
|
18
|
+
"rootMargin",
|
|
19
|
+
"className",
|
|
20
|
+
"children"
|
|
21
|
+
]);
|
|
22
|
+
const reduced = useReducedMotion();
|
|
23
|
+
const { ref, isVisible } = useIntersection({
|
|
24
|
+
threshold,
|
|
25
|
+
rootMargin,
|
|
26
|
+
startVisible: reduced
|
|
27
|
+
});
|
|
28
|
+
const enhanced = React.Children.map(children, (child, i) => {
|
|
29
|
+
var _a2, _b2;
|
|
30
|
+
if (!React.isValidElement(child)) return child;
|
|
31
|
+
const element = child;
|
|
32
|
+
const childClassName = (_a2 = element.props.className) != null ? _a2 : "";
|
|
33
|
+
const childStyle = (_b2 = element.props.style) != null ? _b2 : {};
|
|
34
|
+
return React.cloneElement(element, {
|
|
35
|
+
className: cn(childClassName, "stagger-child"),
|
|
36
|
+
style: __spreadProps(__spreadValues({}, childStyle), {
|
|
37
|
+
// `--stagger-index` e usada por .stagger-revealed .stagger-child no CSS.
|
|
38
|
+
// `--stagger-step-ms` permite override do espacamento por instancia.
|
|
39
|
+
["--stagger-index"]: i,
|
|
40
|
+
["--stagger-step-ms"]: `${step}ms`
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
"div",
|
|
46
|
+
__spreadProps(__spreadValues({
|
|
47
|
+
ref,
|
|
48
|
+
className: cn(isVisible && "stagger-revealed", className)
|
|
49
|
+
}, props), {
|
|
50
|
+
children: enhanced
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { StaggerReveal };
|
|
56
|
+
//# sourceMappingURL=chunk-TPRZMMT6.js.map
|
|
57
|
+
//# sourceMappingURL=chunk-TPRZMMT6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/motion/stagger-reveal.tsx"],"names":["_a","_b"],"mappings":";;;;;;;AAiCA,SAAS,cAAc,EAAA,EAOA;AAPA,EAAA,IAAA,EAAA,GAAA,EAAA,EACrB;AAAA,IAAA,IAAA,GAAO,GAAA;AAAA,IACP,SAAA,GAAY,IAAA;AAAA,IACZ,UAAA,GAAa,kBAAA;AAAA,IACb,SAAA;AAAA,IACA;AAAA,GAtCF,GAiCuB,EAAA,EAMlB,KAAA,GAAA,SAAA,CANkB,EAAA,EAMlB;AAAA,IALH,MAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,EAAA,MAAM,EAAE,GAAA,EAAK,SAAA,EAAU,GAAI,eAAA,CAAgC;AAAA,IACzD,SAAA;AAAA,IACA,UAAA;AAAA,IACA,YAAA,EAAc;AAAA,GACf,CAAA;AAED,EAAA,MAAM,WAAiB,KAAA,CAAA,QAAA,CAAS,GAAA,CAAI,QAAA,EAAU,CAAC,OAAO,CAAA,KAAM;AAhD9D,IAAA,IAAAA,GAAAA,EAAAC,GAAAA;AAiDI,IAAA,IAAI,CAAO,KAAA,CAAA,cAAA,CAAe,KAAK,CAAA,EAAG,OAAO,KAAA;AAEzC,IAAA,MAAM,OAAA,GAAU,KAAA;AAChB,IAAA,MAAM,kBAAiBD,GAAAA,GAAA,OAAA,CAAQ,KAAA,CAAM,SAAA,KAAd,OAAAA,GAAAA,GAA2B,EAAA;AAClD,IAAA,MAAM,cAAkCC,GAAAA,GAAA,OAAA,CAAQ,MAAM,KAAA,KAAd,IAAA,GAAAA,MAAuB,EAAC;AAChE,IAAA,OAAa,mBAAa,OAAA,EAAS;AAAA,MACjC,SAAA,EAAW,EAAA,CAAG,cAAA,EAAgB,eAAe,CAAA;AAAA,MAC7C,KAAA,EAAO,iCACF,UAAA,CAAA,EADE;AAAA;AAAA;AAAA,QAIL,CAAC,iBAA2B,GAAG,CAAA;AAAA,QAC/B,CAAC,mBAA6B,GAAG,CAAA,EAAG,IAAI,CAAA,EAAA;AAAA,OAC1C;AAAA,KACD,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,GAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,SAAA,IAAa,kBAAA,EAAoB,SAAS;AAAA,KAAA,EACpD,KAAA,CAAA,EAHL;AAAA,MAKE,QAAA,EAAA;AAAA,KAAA;AAAA,GACH;AAEJ","file":"chunk-TPRZMMT6.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { useIntersection } from \"@/hooks/use-intersection\"\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\"\n\nexport interface StaggerRevealProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Delay entre cada filho em ms. Default `100`. */\n step?: number\n /** Fracao do container que precisa estar visivel pra disparar. Default `0.15`. */\n threshold?: number\n /** Margin do viewport (CSS shorthand). Default `\"0px 0px -10% 0px\"`. */\n rootMargin?: string\n}\n\n/**\n * Container que anima seus filhos entrando em sequencia (fade-up com delay\n * incremental). Clona cada filho valido e injeta `--stagger-index` como CSS\n * variable; a animacao acontece via `.stagger-child` em `globals.css`.\n *\n * O `step` (default 100ms) controla o espacamento entre cada filho:\n * - 1o filho: delay 0\n * - 2o filho: delay 100ms\n * - 3o filho: delay 200ms ...\n *\n * Note que o `step` so afeta visualmente quando o CSS usa\n * `calc(var(--stagger-index) * Xms)` — atualmente o globals usa `100ms`\n * fixo (o step prop sobrescreve via inline style se necessario).\n *\n * Acessibilidade: respeita `prefers-reduced-motion` — filhos ja entram visiveis.\n */\nfunction StaggerReveal({\n step = 100,\n threshold = 0.15,\n rootMargin = \"0px 0px -10% 0px\",\n className,\n children,\n ...props\n}: StaggerRevealProps) {\n const reduced = useReducedMotion()\n const { ref, isVisible } = useIntersection<HTMLDivElement>({\n threshold,\n rootMargin,\n startVisible: reduced,\n })\n\n const enhanced = React.Children.map(children, (child, i) => {\n if (!React.isValidElement(child)) return child\n type ChildProps = { className?: string; style?: React.CSSProperties }\n const element = child as React.ReactElement<ChildProps>\n const childClassName = element.props.className ?? \"\"\n const childStyle: React.CSSProperties = element.props.style ?? {}\n return React.cloneElement(element, {\n className: cn(childClassName, \"stagger-child\"),\n style: {\n ...childStyle,\n // `--stagger-index` e usada por .stagger-revealed .stagger-child no CSS.\n // `--stagger-step-ms` permite override do espacamento por instancia.\n [\"--stagger-index\" as string]: i,\n [\"--stagger-step-ms\" as string]: `${step}ms`,\n },\n })\n })\n\n return (\n <div\n ref={ref}\n className={cn(isVisible && \"stagger-revealed\", className)}\n {...props}\n >\n {enhanced}\n </div>\n )\n}\n\nexport { StaggerReveal }\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useReducedMotion } from './chunk-K2NUBNSA.js';
|
|
2
|
+
import { useIntersection } from './chunk-XQUQDZVA.js';
|
|
3
|
+
import { cn } from './chunk-TYCPXAXF.js';
|
|
4
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-YINJ5YZ5.js';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function RevealOnScroll(_a) {
|
|
8
|
+
var _b = _a, {
|
|
9
|
+
as = "div",
|
|
10
|
+
delay = 0,
|
|
11
|
+
threshold = 0.15,
|
|
12
|
+
rootMargin = "0px 0px -10% 0px",
|
|
13
|
+
repeat = false,
|
|
14
|
+
className,
|
|
15
|
+
style,
|
|
16
|
+
children
|
|
17
|
+
} = _b, props = __objRest(_b, [
|
|
18
|
+
"as",
|
|
19
|
+
"delay",
|
|
20
|
+
"threshold",
|
|
21
|
+
"rootMargin",
|
|
22
|
+
"repeat",
|
|
23
|
+
"className",
|
|
24
|
+
"style",
|
|
25
|
+
"children"
|
|
26
|
+
]);
|
|
27
|
+
const reduced = useReducedMotion();
|
|
28
|
+
const { ref, isVisible } = useIntersection({
|
|
29
|
+
threshold,
|
|
30
|
+
rootMargin,
|
|
31
|
+
once: !repeat,
|
|
32
|
+
startVisible: reduced
|
|
33
|
+
});
|
|
34
|
+
const Tag = as;
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
Tag,
|
|
37
|
+
__spreadProps(__spreadValues({
|
|
38
|
+
ref,
|
|
39
|
+
className: cn("cycle-reveal", isVisible && "is-visible", className),
|
|
40
|
+
style: delay && !reduced ? __spreadValues({ transitionDelay: `${delay}ms` }, style) : style
|
|
41
|
+
}, props), {
|
|
42
|
+
children
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { RevealOnScroll };
|
|
48
|
+
//# sourceMappingURL=chunk-UJ6OER6O.js.map
|
|
49
|
+
//# sourceMappingURL=chunk-UJ6OER6O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/motion/reveal-on-scroll.tsx"],"names":[],"mappings":";;;;;;AA+BA,SAAS,eAAe,EAAA,EAUA;AAVA,EAAA,IAAA,EAAA,GAAA,EAAA,EACtB;AAAA,IAAA,EAAA,GAAK,KAAA;AAAA,IACL,KAAA,GAAQ,CAAA;AAAA,IACR,SAAA,GAAY,IAAA;AAAA,IACZ,UAAA,GAAa,kBAAA;AAAA,IACb,MAAA,GAAS,KAAA;AAAA,IACT,SAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GAvCF,GA+BwB,EAAA,EASnB,KAAA,GAAA,SAAA,CATmB,EAAA,EASnB;AAAA,IARH,IAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGA,EAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,EAAA,MAAM,EAAE,GAAA,EAAK,SAAA,EAAU,GAAI,eAAA,CAA6B;AAAA,IACtD,SAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAM,CAAC,MAAA;AAAA,IACP,YAAA,EAAc;AAAA,GACf,CAAA;AAED,EAAA,MAAM,GAAA,GAAM,EAAA;AACZ,EAAA,uBACE,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA,aAAA,CAAA,cAAA,CAAA;AAAA,MACC,GAAA;AAAA,MACA,SAAA,EAAW,EAAA,CAAG,cAAA,EAAgB,SAAA,IAAa,cAAc,SAAS,CAAA;AAAA,MAClE,KAAA,EAAO,SAAS,CAAC,OAAA,GAAU,iBAAE,eAAA,EAAiB,CAAA,EAAG,KAAK,CAAA,EAAA,CAAA,EAAA,EAAS,KAAA,CAAA,GAAU;AAAA,KAAA,EACrE,KAAA,CAAA,EAJL;AAAA,MAME;AAAA,KAAA;AAAA,GACH;AAEJ","file":"chunk-UJ6OER6O.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { useIntersection } from \"@/hooks/use-intersection\"\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\"\n\ntype AsTag = \"div\" | \"section\" | \"article\" | \"header\" | \"footer\" | \"main\" | \"aside\"\n\nexport interface RevealOnScrollProps extends React.HTMLAttributes<HTMLElement> {\n /** Tag HTML renderizada. Default `\"div\"`. */\n as?: AsTag\n /** Delay extra em ms antes de iniciar a animacao. Default `0`. */\n delay?: number\n /** Fracao do elemento que precisa estar visivel pra disparar. Default `0.15`. */\n threshold?: number\n /** Margin do viewport (CSS shorthand). Default `\"0px 0px -10% 0px\"`. */\n rootMargin?: string\n /** Repetir a animacao toda vez que reentrar no viewport. Default `false`. */\n repeat?: boolean\n}\n\n/**\n * Envelopa qualquer conteudo e aplica fade-up suave quando o elemento entra\n * no viewport. Usa a utility `.cycle-reveal` definida em `globals.css` (que\n * faz `opacity 0 → 1` e `translateY(8px → 0)` com `--duration-reveal`).\n *\n * Acessibilidade: respeita `prefers-reduced-motion` — quando habilitado,\n * o conteudo fica imediatamente visivel sem transicao.\n */\nfunction RevealOnScroll({\n as = \"div\",\n delay = 0,\n threshold = 0.15,\n rootMargin = \"0px 0px -10% 0px\",\n repeat = false,\n className,\n style,\n children,\n ...props\n}: RevealOnScrollProps) {\n const reduced = useReducedMotion()\n const { ref, isVisible } = useIntersection<HTMLElement>({\n threshold,\n rootMargin,\n once: !repeat,\n startVisible: reduced,\n })\n\n const Tag = as as React.ElementType\n return (\n <Tag\n ref={ref}\n className={cn(\"cycle-reveal\", isVisible && \"is-visible\", className)}\n style={delay && !reduced ? { transitionDelay: `${delay}ms`, ...style } : style}\n {...props}\n >\n {children}\n </Tag>\n )\n}\n\nexport { RevealOnScroll }\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cn } from './chunk-TYCPXAXF.js';
|
|
2
|
+
import { __objRest, __spreadValues } from './chunk-YINJ5YZ5.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var CardDarkGlow = React.forwardRef(
|
|
7
|
+
function CardDarkGlow2(_a, ref) {
|
|
8
|
+
var _b = _a, { as = "div", interactive = true, className } = _b, props = __objRest(_b, ["as", "interactive", "className"]);
|
|
9
|
+
const Tag = as;
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
Tag,
|
|
12
|
+
__spreadValues({
|
|
13
|
+
ref,
|
|
14
|
+
"data-slot": "card-dark-glow",
|
|
15
|
+
"data-interactive": interactive ? "true" : "false",
|
|
16
|
+
className: cn("cycle-card-dark-glow", className)
|
|
17
|
+
}, props)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export { CardDarkGlow };
|
|
23
|
+
//# sourceMappingURL=chunk-VXWMC2NK.js.map
|
|
24
|
+
//# sourceMappingURL=chunk-VXWMC2NK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/effects/card-dark-glow.tsx"],"names":["CardDarkGlow"],"mappings":";;;;;AA+BA,IAAM,YAAA,GAAqB,KAAA,CAAA,UAAA;AAAA,EACzB,SAASA,aAAAA,CAAa,EAAA,EAAyD,GAAA,EAAK;AAA9D,IAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAA,EAAA,GAAK,KAAA,EAAO,WAAA,GAAc,IAAA,EAAM,SAAA,EAhC1D,GAgCwB,EAAA,EAAgD,KAAA,GAAA,SAAA,CAAhD,EAAA,EAAgD,CAA9C,IAAA,EAAY,aAAA,EAAoB,WAAA,CAAA,CAAA;AACtD,IAAA,MAAM,GAAA,GAAM,EAAA;AACZ,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA,cAAA,CAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,gBAAA;AAAA,QACV,kBAAA,EAAkB,cAAc,MAAA,GAAS,OAAA;AAAA,QACzC,SAAA,EAAW,EAAA,CAAG,sBAAA,EAAwB,SAAS;AAAA,OAAA,EAC3C,KAAA;AAAA,KACN;AAAA,EAEJ;AACF","file":"chunk-VXWMC2NK.js","sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype CardDarkGlowTag = \"div\" | \"article\" | \"section\"\n\nexport interface CardDarkGlowProps extends React.HTMLAttributes<HTMLElement> {\n /** Tag renderizada. Default `\"div\"`. */\n as?: CardDarkGlowTag\n /**\n * Habilita lift visual no hover (`translateY(-3px)` + glow mais forte).\n * Default `true`. Use `false` em cards que sao apenas conteudo (sem ser link/clicavel).\n */\n interactive?: boolean\n}\n\n/**\n * Wrapper de card com inset highlight + sombra com glow rose subtil + hover\n * lift opcional. Pareie com `CircleGlow` (no container externo) pra entregar o\n * efeito \"dark premium\" que repete pelas dobras do corporate.\n *\n * @example\n * <CardDarkGlow className=\"rounded-2xl bg-card border p-6\">\n * <h3>Titulo</h3>\n * <p>Descricao do card</p>\n * </CardDarkGlow>\n *\n * <CardDarkGlow as=\"article\" interactive={false}>\n * ...card nao-interativo, sem hover lift\n * </CardDarkGlow>\n */\nconst CardDarkGlow = React.forwardRef<HTMLElement, CardDarkGlowProps>(\n function CardDarkGlow({ as = \"div\", interactive = true, className, ...props }, ref) {\n const Tag = as as React.ElementType\n return (\n <Tag\n ref={ref}\n data-slot=\"card-dark-glow\"\n data-interactive={interactive ? \"true\" : \"false\"}\n className={cn(\"cycle-card-dark-glow\", className)}\n {...props}\n />\n )\n }\n)\n\nexport { CardDarkGlow }\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { cn } from './chunk-TYCPXAXF.js';
|
|
2
|
+
import { __objRest, __spreadValues } from './chunk-YINJ5YZ5.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var SectionEyebrow = React.forwardRef(
|
|
7
|
+
function SectionEyebrow2(_a, ref) {
|
|
8
|
+
var _b = _a, { as = "p", align = "left", className } = _b, props = __objRest(_b, ["as", "align", "className"]);
|
|
9
|
+
const Tag = as;
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
Tag,
|
|
12
|
+
__spreadValues({
|
|
13
|
+
ref,
|
|
14
|
+
"data-slot": "section-eyebrow",
|
|
15
|
+
className: cn(
|
|
16
|
+
"text-xs font-mono uppercase tracking-widest text-muted-foreground",
|
|
17
|
+
align === "center" && "text-center",
|
|
18
|
+
className
|
|
19
|
+
)
|
|
20
|
+
}, props)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export { SectionEyebrow };
|
|
26
|
+
//# sourceMappingURL=chunk-VYHRNO77.js.map
|
|
27
|
+
//# sourceMappingURL=chunk-VYHRNO77.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/typography/section-eyebrow.tsx"],"names":["SectionEyebrow"],"mappings":";;;;;AAsBA,IAAM,cAAA,GAAuB,KAAA,CAAA,UAAA;AAAA,EAC3B,SAASA,eAAAA,CAAe,EAAA,EAAmD,GAAA,EAAK;AAAxD,IAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAA,EAAA,GAAK,GAAA,EAAK,KAAA,GAAQ,MAAA,EAAQ,SAAA,EAvBtD,GAuB0B,EAAA,EAA0C,KAAA,GAAA,SAAA,CAA1C,EAAA,EAA0C,CAAxC,IAAA,EAAU,OAAA,EAAgB,WAAA,CAAA,CAAA;AAClD,IAAA,MAAM,GAAA,GAAM,EAAA;AACZ,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA,cAAA,CAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,iBAAA;AAAA,QACV,SAAA,EAAW,EAAA;AAAA,UACT,mEAAA;AAAA,UACA,UAAU,QAAA,IAAY,aAAA;AAAA,UACtB;AAAA;AACF,OAAA,EACI,KAAA;AAAA,KACN;AAAA,EAEJ;AACF","file":"chunk-VYHRNO77.js","sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype SectionEyebrowTag = \"p\" | \"span\" | \"div\"\n\nexport interface SectionEyebrowProps extends React.HTMLAttributes<HTMLElement> {\n /** Tag renderizada. Default `\"p\"`. */\n as?: SectionEyebrowTag\n /** Alinhamento. Default `\"left\"`. */\n align?: \"left\" | \"center\"\n}\n\n/**\n * Rotulo monospace acima do `SectionHeading` — funciona como \"eyebrow\" que\n * categoriza a dobra (ex: \"Nossa solucao\", \"Para empresas\"). Tipografia\n * conservadora pra nao competir com o heading principal.\n *\n * @example\n * <SectionEyebrow align=\"center\">Para empresas</SectionEyebrow>\n * <SectionHeading>Acelere o ingles do seu time</SectionHeading>\n */\nconst SectionEyebrow = React.forwardRef<HTMLElement, SectionEyebrowProps>(\n function SectionEyebrow({ as = \"p\", align = \"left\", className, ...props }, ref) {\n const Tag = as as React.ElementType\n return (\n <Tag\n ref={ref}\n data-slot=\"section-eyebrow\"\n className={cn(\n \"text-xs font-mono uppercase tracking-widest text-muted-foreground\",\n align === \"center\" && \"text-center\",\n className\n )}\n {...props}\n />\n )\n }\n)\n\nexport { SectionEyebrow }\n"]}
|