@fluencypassdevs/cycle 1.15.1 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mcp.mjs +94 -0
- package/dist/chunk-DJ3DMPKK.js +56 -0
- package/dist/chunk-DJ3DMPKK.js.map +1 -0
- package/dist/chunk-G57PPNB3.js +74 -0
- package/dist/chunk-G57PPNB3.js.map +1 -0
- package/dist/chunk-JQRGW2RF.js +82 -0
- package/dist/chunk-JQRGW2RF.js.map +1 -0
- package/dist/chunk-WCDYTWKA.js +105 -0
- package/dist/chunk-WCDYTWKA.js.map +1 -0
- package/dist/chunk-YZNOE4TO.js +48 -0
- package/dist/chunk-YZNOE4TO.js.map +1 -0
- package/dist/marketing/buttons/cta-brand.d.ts +39 -0
- package/dist/marketing/buttons/cta-brand.js +8 -0
- package/dist/marketing/buttons/cta-brand.js.map +1 -0
- package/dist/marketing/buttons/index.d.ts +5 -0
- package/dist/marketing/buttons/index.js +9 -0
- package/dist/marketing/buttons/index.js.map +1 -0
- package/dist/marketing/buttons/link-brand.d.ts +39 -0
- package/dist/marketing/buttons/link-brand.js +6 -0
- package/dist/marketing/buttons/link-brand.js.map +1 -0
- package/dist/marketing/effects/hand-underline.d.ts +33 -0
- package/dist/marketing/effects/hand-underline.js +8 -0
- package/dist/marketing/effects/hand-underline.js.map +1 -0
- package/dist/marketing/effects/index.d.ts +3 -0
- package/dist/marketing/effects/index.js +5 -0
- package/dist/marketing/effects/magnetic-button.d.ts +36 -0
- package/dist/marketing/effects/magnetic-button.js +7 -0
- package/dist/marketing/effects/magnetic-button.js.map +1 -0
- package/dist/marketing/effects/rotating-word.d.ts +40 -0
- package/dist/marketing/effects/rotating-word.js +7 -0
- package/dist/marketing/effects/rotating-word.js.map +1 -0
- package/dist/styles/tokens.css +37 -8
- package/package.json +9 -1
package/bin/mcp.mjs
CHANGED
|
@@ -1142,6 +1142,100 @@ import { Home, Search } from "@fluencypassdevs/cycle/icons/lucide"
|
|
|
1142
1142
|
</Marquee>`,
|
|
1143
1143
|
keywords: ["marketing", "landing", "effects", "marquee", "scroll", "horizontal", "logo", "cloud", "partner", "band"],
|
|
1144
1144
|
},
|
|
1145
|
+
// ─── Marketing — Camada 2b (Buttons + Motion avançado) ──────────────────────
|
|
1146
|
+
{
|
|
1147
|
+
name: "MagneticButton",
|
|
1148
|
+
import: `import { MagneticButton } from "@fluencypassdevs/cycle/marketing/effects/magnetic-button"`,
|
|
1149
|
+
description: "MARKETING — Camada 2b. Wrapper que aplica efeito magnetico no filho (puxa em direcao ao cursor). Escreve transform direto no DOM via ref + RAF throttle. IntersectionObserver gating (rootMargin 200px). Drop-shadow rose via CSS vars --shadow-brand-glow-idle/-hover (consumer override). Skip total em prefers-reduced-motion e pointer:coarse (touch).",
|
|
1150
|
+
props: [
|
|
1151
|
+
{ name: "strength", type: "number", default: "0.25", note: "multiplicador do offset" },
|
|
1152
|
+
{ name: "radius", type: "number", default: "100", note: "distancia em px na qual o efeito ativa" },
|
|
1153
|
+
],
|
|
1154
|
+
example: `<MagneticButton>
|
|
1155
|
+
<a href="#vendas">
|
|
1156
|
+
<Button variant="default">Quero saber mais</Button>
|
|
1157
|
+
</a>
|
|
1158
|
+
</MagneticButton>
|
|
1159
|
+
|
|
1160
|
+
<MagneticButton strength={0.4} radius={150}>
|
|
1161
|
+
<CustomElement />
|
|
1162
|
+
</MagneticButton>`,
|
|
1163
|
+
keywords: ["marketing", "landing", "effects", "magnetic", "hover", "cursor", "interactive", "premium"],
|
|
1164
|
+
},
|
|
1165
|
+
{
|
|
1166
|
+
name: "RotatingWord",
|
|
1167
|
+
import: `import { RotatingWord } from "@fluencypassdevs/cycle/marketing/effects/rotating-word"`,
|
|
1168
|
+
description: "MARKETING — Camada 2b. Typewriter de palavras em loop (typing → holding → erasing). Cor herda do parent via currentColor (consumer aplica text-[color]). aria-live polite + aria-atomic. Em prefers-reduced-motion, mostra so primeira palavra estatica sem cursor.",
|
|
1169
|
+
props: [
|
|
1170
|
+
{ name: "words", type: "string[]", default: "-", note: "obrigatorio, palavras a ciclar" },
|
|
1171
|
+
{ name: "typingMs", type: "number", default: "80", note: "velocidade de digitacao ms/caractere" },
|
|
1172
|
+
{ name: "eraseMs", type: "number", default: "45", note: "velocidade de apagar" },
|
|
1173
|
+
{ name: "holdMs", type: "number", default: "1500", note: "tempo segurando a palavra completa" },
|
|
1174
|
+
],
|
|
1175
|
+
example: `<h1>
|
|
1176
|
+
Aprenda ingles com{" "}
|
|
1177
|
+
<RotatingWord
|
|
1178
|
+
className="text-[color:var(--brand-default)]"
|
|
1179
|
+
words={["IA", "proposito", "confianca"]}
|
|
1180
|
+
/>
|
|
1181
|
+
</h1>`,
|
|
1182
|
+
keywords: ["marketing", "landing", "effects", "typewriter", "rotating", "word", "hero", "typing"],
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
name: "HandUnderline",
|
|
1186
|
+
import: `import { HandUnderline } from "@fluencypassdevs/cycle/marketing/effects/hand-underline"`,
|
|
1187
|
+
description: "MARKETING — Camada 2b. Wrapper que desenha SVG underline em curva sutil abaixo do texto, animada via stroke-dasharray quando entra no viewport (threshold 0.6). Cor herda do parent (stroke=currentColor). Em prefers-reduced-motion, desenha completo direto sem animar.",
|
|
1188
|
+
props: [
|
|
1189
|
+
{ name: "delay", type: "number", default: "600", note: "ms entre intersecao e inicio do draw" },
|
|
1190
|
+
{ name: "duration", type: "number", default: "780", note: "duracao do draw em ms" },
|
|
1191
|
+
],
|
|
1192
|
+
example: `<h2>
|
|
1193
|
+
Acelere o ingles do seu{" "}
|
|
1194
|
+
<HandUnderline className="text-[color:var(--brand-default)]">
|
|
1195
|
+
time corporativo
|
|
1196
|
+
</HandUnderline>
|
|
1197
|
+
</h2>`,
|
|
1198
|
+
keywords: ["marketing", "landing", "effects", "underline", "highlight", "draw", "scroll-trigger"],
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
name: "CtaBrand",
|
|
1202
|
+
import: `import { CtaBrand } from "@fluencypassdevs/cycle/marketing/buttons/cta-brand"`,
|
|
1203
|
+
description: "MARKETING — Camada 2b. CTA principal de marketing — gradient brand rose (from-brand-soft to-brand-dark) + rounded-full + drop-shadow glow + brightness hover + MagneticButton embutido (sempre). Sempre renderiza como <a> com href. Pra acoes de JS sem URL, use Button core.",
|
|
1204
|
+
props: [
|
|
1205
|
+
{ name: "href", type: "string", default: "-", note: "obrigatorio, sempre renderiza como <a>" },
|
|
1206
|
+
{ name: "external", type: "boolean", default: "false", note: "target=_blank + rel noopener noreferrer" },
|
|
1207
|
+
{ name: "size", type: '"md" | "lg"', default: '"lg"', note: "md=h-11 px-7. lg=h-13 px-10" },
|
|
1208
|
+
{ name: "disableMagnetic", type: "boolean", default: "false", note: "escape hatch raro (popups/drawers)" },
|
|
1209
|
+
],
|
|
1210
|
+
example: `<CtaBrand href="#vendas">
|
|
1211
|
+
Solicitar demonstracao
|
|
1212
|
+
</CtaBrand>
|
|
1213
|
+
|
|
1214
|
+
<CtaBrand href="https://app.fluencypass.com" external size="md">
|
|
1215
|
+
Acessar app
|
|
1216
|
+
</CtaBrand>`,
|
|
1217
|
+
keywords: ["marketing", "landing", "buttons", "cta", "brand", "gradient", "magnetic", "hero", "conversao"],
|
|
1218
|
+
},
|
|
1219
|
+
{
|
|
1220
|
+
name: "LinkBrand",
|
|
1221
|
+
import: `import { LinkBrand } from "@fluencypassdevs/cycle/marketing/buttons/link-brand"`,
|
|
1222
|
+
description: "MARKETING — Camada 2b. Link de texto discreto da marca — text-brand-default com hover pra brand-dark, transition-colors, focus-visible outline. Sem underline por default (consumer adiciona hover:underline se quiser). Renderiza como <a> (default) ou <button> via prop as.",
|
|
1223
|
+
props: [
|
|
1224
|
+
{ name: "as", type: '"a" | "button"', default: '"a"' },
|
|
1225
|
+
{ name: "href", type: "string", default: "-", note: "obrigatorio quando as=a" },
|
|
1226
|
+
{ name: "external", type: "boolean", default: "false" },
|
|
1227
|
+
],
|
|
1228
|
+
example: `<LinkBrand href="/precos">Ver planos</LinkBrand>
|
|
1229
|
+
|
|
1230
|
+
<LinkBrand href="https://twitter.com" external>
|
|
1231
|
+
Siga no Twitter
|
|
1232
|
+
</LinkBrand>
|
|
1233
|
+
|
|
1234
|
+
<LinkBrand as="button" onClick={() => openModal()}>
|
|
1235
|
+
Abrir filtros
|
|
1236
|
+
</LinkBrand>`,
|
|
1237
|
+
keywords: ["marketing", "landing", "buttons", "link", "brand", "nav", "footer", "inline"],
|
|
1238
|
+
},
|
|
1145
1239
|
]
|
|
1146
1240
|
|
|
1147
1241
|
// ─── Design Tokens ─────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { MagneticButton } from './chunk-WCDYTWKA.js';
|
|
2
|
+
import { cn } from './chunk-QTH4LSO6.js';
|
|
3
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-2NMEKWO5.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { cva } from 'class-variance-authority';
|
|
6
|
+
import { jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var ctaBrandVariants = cva(
|
|
9
|
+
[
|
|
10
|
+
// Base
|
|
11
|
+
"inline-flex items-center justify-center gap-2",
|
|
12
|
+
"rounded-full font-semibold whitespace-nowrap",
|
|
13
|
+
"text-white border-0",
|
|
14
|
+
// Brand gradient (consome tokens --brand-soft/--brand-dark da Camada 2a)
|
|
15
|
+
"bg-gradient-to-b from-[color:var(--brand-soft)] to-[color:var(--brand-dark)]",
|
|
16
|
+
"hover:brightness-110 transition-[filter] duration-200",
|
|
17
|
+
// A11y focus
|
|
18
|
+
"outline-none focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
19
|
+
"focus-visible:outline-[color:var(--brand-default)]"
|
|
20
|
+
].join(" "),
|
|
21
|
+
{
|
|
22
|
+
variants: {
|
|
23
|
+
size: {
|
|
24
|
+
md: "h-11 px-7 text-sm",
|
|
25
|
+
lg: "h-13 px-10 text-base"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: {
|
|
29
|
+
size: "lg"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
var CtaBrand = React.forwardRef(
|
|
34
|
+
function CtaBrand2(_a, ref) {
|
|
35
|
+
var _b = _a, { href, external = false, size, disableMagnetic = false, className, children } = _b, props = __objRest(_b, ["href", "external", "size", "disableMagnetic", "className", "children"]);
|
|
36
|
+
const anchor = /* @__PURE__ */ jsx(
|
|
37
|
+
"a",
|
|
38
|
+
__spreadProps(__spreadValues({
|
|
39
|
+
ref,
|
|
40
|
+
href,
|
|
41
|
+
target: external ? "_blank" : void 0,
|
|
42
|
+
rel: external ? "noopener noreferrer" : void 0,
|
|
43
|
+
"data-slot": "cta-brand",
|
|
44
|
+
className: cn(ctaBrandVariants({ size }), className)
|
|
45
|
+
}, props), {
|
|
46
|
+
children
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
if (disableMagnetic) return anchor;
|
|
50
|
+
return /* @__PURE__ */ jsx(MagneticButton, { children: anchor });
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export { CtaBrand, ctaBrandVariants };
|
|
55
|
+
//# sourceMappingURL=chunk-DJ3DMPKK.js.map
|
|
56
|
+
//# sourceMappingURL=chunk-DJ3DMPKK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/buttons/cta-brand.tsx"],"names":["CtaBrand"],"mappings":";;;;;;;AAQA,IAAM,gBAAA,GAAmB,GAAA;AAAA,EACvB;AAAA;AAAA,IAEE,+CAAA;AAAA,IACA,8CAAA;AAAA,IACA,qBAAA;AAAA;AAAA,IAEA,8EAAA;AAAA,IACA,uDAAA;AAAA;AAAA,IAEA,qEAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,GAAG,CAAA;AAAA,EACV;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,mBAAA;AAAA,QACJ,EAAA,EAAI;AAAA;AACN,KACF;AAAA,IACA,eAAA,EAAiB;AAAA,MACf,IAAA,EAAM;AAAA;AACR;AAEJ;AAkCA,IAAM,QAAA,GAAiB,KAAA,CAAA,UAAA;AAAA,EACrB,SAASA,SAAAA,CACP,EAAA,EACA,GAAA,EACA;AAFA,IAAA,IAAA,EAAA,GAAA,EAAA,EAAE,QAAM,QAAA,GAAW,KAAA,EAAO,IAAA,EAAM,eAAA,GAAkB,OAAO,SAAA,EAAW,QAAA,EApExE,GAoEI,EAAA,EAAiF,kBAAjF,EAAA,EAAiF,CAA/E,QAAM,UAAA,EAAkB,MAAA,EAAM,mBAAyB,WAAA,EAAW,UAAA,CAAA,CAAA;AAGpE,IAAA,MAAM,MAAA,mBACJ,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA,aAAA,CAAA,cAAA,CAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAA,EAAQ,WAAW,QAAA,GAAW,MAAA;AAAA,QAC9B,GAAA,EAAK,WAAW,qBAAA,GAAwB,MAAA;AAAA,QACxC,WAAA,EAAU,WAAA;AAAA,QACV,WAAW,EAAA,CAAG,gBAAA,CAAiB,EAAE,IAAA,EAAM,GAAG,SAAS;AAAA,OAAA,EAC/C,KAAA,CAAA,EAPL;AAAA,QASE;AAAA,OAAA;AAAA,KACH;AAGF,IAAA,IAAI,iBAAiB,OAAO,MAAA;AAC5B,IAAA,uBAAO,GAAA,CAAC,kBAAgB,QAAA,EAAA,MAAA,EAAO,CAAA;AAAA,EACjC;AACF","file":"chunk-DJ3DMPKK.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { MagneticButton } from \"@/components/marketing/effects/magnetic-button\"\n\nconst ctaBrandVariants = cva(\n [\n // Base\n \"inline-flex items-center justify-center gap-2\",\n \"rounded-full font-semibold whitespace-nowrap\",\n \"text-white border-0\",\n // Brand gradient (consome tokens --brand-soft/--brand-dark da Camada 2a)\n \"bg-gradient-to-b from-[color:var(--brand-soft)] to-[color:var(--brand-dark)]\",\n \"hover:brightness-110 transition-[filter] duration-200\",\n // A11y focus\n \"outline-none focus-visible:outline-2 focus-visible:outline-offset-2\",\n \"focus-visible:outline-[color:var(--brand-default)]\",\n ].join(\" \"),\n {\n variants: {\n size: {\n md: \"h-11 px-7 text-sm\",\n lg: \"h-13 px-10 text-base\",\n },\n },\n defaultVariants: {\n size: \"lg\",\n },\n }\n)\n\nexport interface CtaBrandProps\n extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, \"size\">,\n VariantProps<typeof ctaBrandVariants> {\n /** URL destino. Sempre renderiza como `<a>`. Pra acao de JS sem URL, use `<Button>` core. */\n href: string\n /** Quando true, abre em nova aba com `rel=\"noopener noreferrer\"`. Default `false`. */\n external?: boolean\n /**\n * Escape hatch — desliga o efeito magnetic wrapper. Use em contextos onde o\n * movimento incomoda (dentro de Sheet/Drawer/popover). Default `false`\n * (magnetic SEMPRE ligado — esse e o ponto do CtaBrand).\n */\n disableMagnetic?: boolean\n}\n\n/**\n * CTA principal de marketing — botao com gradient brand rose (Fluencypass),\n * rounded-full, drop-shadow glow + brightness hover, e efeito magnetic\n * embutido (puxa em direcao ao cursor).\n *\n * Pra acoes de JS sem URL (submit de form, abrir modal etc), use o\n * `<Button>` core do Cycle em vez disso.\n *\n * @example\n * <CtaBrand href=\"#vendas\">\n * Solicitar demonstracao\n * </CtaBrand>\n *\n * <CtaBrand href=\"https://app.fluencypass.com\" external size=\"md\">\n * Acessar app\n * </CtaBrand>\n */\nconst CtaBrand = React.forwardRef<HTMLAnchorElement, CtaBrandProps>(\n function CtaBrand(\n { href, external = false, size, disableMagnetic = false, className, children, ...props },\n ref\n ) {\n const anchor = (\n <a\n ref={ref}\n href={href}\n target={external ? \"_blank\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n data-slot=\"cta-brand\"\n className={cn(ctaBrandVariants({ size }), className)}\n {...props}\n >\n {children}\n </a>\n )\n\n if (disableMagnetic) return anchor\n return <MagneticButton>{anchor}</MagneticButton>\n }\n)\n\nexport { CtaBrand, ctaBrandVariants }\n"]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useReducedMotion } from './chunk-T7EIAVSF.js';
|
|
2
|
+
import { useIntersection } from './chunk-OHRYR7PN.js';
|
|
3
|
+
import { cn } from './chunk-QTH4LSO6.js';
|
|
4
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-2NMEKWO5.js';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var PATH_LENGTH = 240;
|
|
9
|
+
var STROKE_WIDTH = 2.2;
|
|
10
|
+
var SVG_PATH = "M 2 9 C 30 4, 70 12, 110 7 S 180 4, 198 8";
|
|
11
|
+
var SVG_VIEWBOX = "0 0 200 14";
|
|
12
|
+
var HandUnderline = React.forwardRef(
|
|
13
|
+
function HandUnderline2(_a, forwardedRef) {
|
|
14
|
+
var _b = _a, { delay = 600, duration = 780, className, children } = _b, props = __objRest(_b, ["delay", "duration", "className", "children"]);
|
|
15
|
+
const reduced = useReducedMotion();
|
|
16
|
+
const { ref, isVisible } = useIntersection({
|
|
17
|
+
threshold: 0.6,
|
|
18
|
+
rootMargin: "0px",
|
|
19
|
+
startVisible: reduced
|
|
20
|
+
});
|
|
21
|
+
const [draw, setDraw] = React.useState(reduced);
|
|
22
|
+
React.useImperativeHandle(forwardedRef, () => ref.current, [ref]);
|
|
23
|
+
React.useEffect(() => {
|
|
24
|
+
if (!isVisible || draw) return;
|
|
25
|
+
if (reduced) {
|
|
26
|
+
setDraw(true);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const id = window.setTimeout(() => setDraw(true), delay);
|
|
30
|
+
return () => window.clearTimeout(id);
|
|
31
|
+
}, [isVisible, draw, delay, reduced]);
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
"span",
|
|
34
|
+
__spreadProps(__spreadValues({
|
|
35
|
+
ref,
|
|
36
|
+
"data-slot": "hand-underline",
|
|
37
|
+
className: cn("relative inline-block whitespace-nowrap", className)
|
|
38
|
+
}, props), {
|
|
39
|
+
children: [
|
|
40
|
+
children,
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
"svg",
|
|
43
|
+
{
|
|
44
|
+
"aria-hidden": "true",
|
|
45
|
+
viewBox: SVG_VIEWBOX,
|
|
46
|
+
preserveAspectRatio: "none",
|
|
47
|
+
className: "absolute left-0 right-0 -bottom-1 w-full pointer-events-none",
|
|
48
|
+
style: { height: "0.32em" },
|
|
49
|
+
children: /* @__PURE__ */ jsx(
|
|
50
|
+
"path",
|
|
51
|
+
{
|
|
52
|
+
d: SVG_PATH,
|
|
53
|
+
fill: "none",
|
|
54
|
+
stroke: "currentColor",
|
|
55
|
+
strokeWidth: STROKE_WIDTH,
|
|
56
|
+
strokeLinecap: "round",
|
|
57
|
+
style: {
|
|
58
|
+
strokeDasharray: PATH_LENGTH,
|
|
59
|
+
strokeDashoffset: draw ? 0 : PATH_LENGTH,
|
|
60
|
+
transition: reduced ? "none" : `stroke-dashoffset ${duration}ms cubic-bezier(0.22, 1, 0.36, 1)`
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
]
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export { HandUnderline };
|
|
73
|
+
//# sourceMappingURL=chunk-G57PPNB3.js.map
|
|
74
|
+
//# sourceMappingURL=chunk-G57PPNB3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/effects/hand-underline.tsx"],"names":["HandUnderline"],"mappings":";;;;;;;AAiBA,IAAM,WAAA,GAAc,GAAA;AACpB,IAAM,YAAA,GAAe,GAAA;AACrB,IAAM,QAAA,GAAW,2CAAA;AACjB,IAAM,WAAA,GAAc,YAAA;AAuBpB,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA;AAAA,EAC1B,SAASA,cAAAA,CACP,EAAA,EACA,YAAA,EACA;AAFA,IAAA,IAAA,EAAA,GAAA,EAAA,EAAE,EAAA,KAAA,GAAQ,GAAA,EAAK,QAAA,GAAW,GAAA,EAAK,SAAA,EAAW,QAAA,EA7C9C,GA6CI,EAAA,EAAuD,KAAA,GAAA,SAAA,CAAvD,EAAA,EAAuD,CAArD,OAAA,EAAa,YAAgB,WAAA,EAAW,UAAA,CAAA,CAAA;AAG1C,IAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,IAAA,MAAM,EAAE,GAAA,EAAK,SAAA,EAAU,GAAI,eAAA,CAAiC;AAAA,MAC1D,SAAA,EAAW,GAAA;AAAA,MACX,UAAA,EAAY,KAAA;AAAA,MACZ,YAAA,EAAc;AAAA,KACf,CAAA;AACD,IAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAU,eAAS,OAAO,CAAA;AAG9C,IAAM,0BAAoB,YAAA,EAAc,MAAM,IAAI,OAAA,EAA4B,CAAC,GAAG,CAAC,CAAA;AAEnF,IAAM,gBAAU,MAAM;AACpB,MAAA,IAAI,CAAC,aAAa,IAAA,EAAM;AACxB,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,QAAA;AAAA,MACF;AACA,MAAA,MAAM,KAAK,MAAA,CAAO,UAAA,CAAW,MAAM,OAAA,CAAQ,IAAI,GAAG,KAAK,CAAA;AACvD,MAAA,OAAO,MAAM,MAAA,CAAO,YAAA,CAAa,EAAE,CAAA;AAAA,IACrC,GAAG,CAAC,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,OAAO,CAAC,CAAA;AAEpC,IAAA,uBACE,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA,aAAA,CAAA,cAAA,CAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,gBAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,yCAAA,EAA2C,SAAS;AAAA,OAAA,EAC9D,KAAA,CAAA,EAJL;AAAA,QAME,QAAA,EAAA;AAAA,UAAA,QAAA;AAAA,0BACD,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,aAAA,EAAY,MAAA;AAAA,cACZ,OAAA,EAAS,WAAA;AAAA,cACT,mBAAA,EAAoB,MAAA;AAAA,cACpB,SAAA,EAAU,8DAAA;AAAA,cACV,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAA,EAAS;AAAA,cAE1B,QAAA,kBAAA,GAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,CAAA,EAAG,QAAA;AAAA,kBACH,IAAA,EAAK,MAAA;AAAA,kBACL,MAAA,EAAO,cAAA;AAAA,kBACP,WAAA,EAAa,YAAA;AAAA,kBACb,aAAA,EAAc,OAAA;AAAA,kBACd,KAAA,EAAO;AAAA,oBACL,eAAA,EAAiB,WAAA;AAAA,oBACjB,gBAAA,EAAkB,OAAO,CAAA,GAAI,WAAA;AAAA,oBAC7B,UAAA,EAAY,OAAA,GACR,MAAA,GACA,CAAA,kBAAA,EAAqB,QAAQ,CAAA,iCAAA;AAAA;AACnC;AAAA;AACF;AAAA;AACF;AAAA,OAAA;AAAA,KACF;AAAA,EAEJ;AACF","file":"chunk-G57PPNB3.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\"\nimport { useIntersection } from \"@/hooks/use-intersection\"\n\nexport interface HandUnderlineProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Delay em ms entre intersecao no viewport e inicio do draw. Default `600`. */\n delay?: number\n /** Duracao do draw em ms (stroke-dashoffset 240 → 0). Default `780`. */\n duration?: number\n children: React.ReactNode\n}\n\nconst PATH_LENGTH = 240\nconst STROKE_WIDTH = 2.2\nconst SVG_PATH = \"M 2 9 C 30 4, 70 12, 110 7 S 180 4, 198 8\"\nconst SVG_VIEWBOX = \"0 0 200 14\"\n\n/**\n * Wrapper que desenha um underline SVG em curva sutil abaixo do texto, animado\n * via stroke-dasharray quando entra no viewport. Util pra dar enfase em\n * palavras-chave em headings sem usar bold/color.\n *\n * Cor do stroke: `currentColor` — herda do parent. Wrappa com\n * `<span className=\"text-[color:var(--brand-default)]\">` ou outra cor.\n *\n * Acessibilidade:\n * - SVG `aria-hidden` (decorativo).\n * - `prefers-reduced-motion: reduce` — desenha o underline completo direto,\n * sem animar.\n *\n * @example\n * <h2>\n * Acelere o ingles do seu{\" \"}\n * <HandUnderline className=\"text-[color:var(--brand-default)]\">\n * time corporativo\n * </HandUnderline>\n * </h2>\n */\nconst HandUnderline = React.forwardRef<HTMLSpanElement, HandUnderlineProps>(\n function HandUnderline(\n { delay = 600, duration = 780, className, children, ...props },\n forwardedRef\n ) {\n const reduced = useReducedMotion()\n const { ref, isVisible } = useIntersection<HTMLSpanElement>({\n threshold: 0.6,\n rootMargin: \"0px\",\n startVisible: reduced,\n })\n const [draw, setDraw] = React.useState(reduced)\n\n // Combina forwarded ref + ref interno do useIntersection.\n React.useImperativeHandle(forwardedRef, () => ref.current as HTMLSpanElement, [ref])\n\n React.useEffect(() => {\n if (!isVisible || draw) return\n if (reduced) {\n setDraw(true)\n return\n }\n const id = window.setTimeout(() => setDraw(true), delay)\n return () => window.clearTimeout(id)\n }, [isVisible, draw, delay, reduced])\n\n return (\n <span\n ref={ref}\n data-slot=\"hand-underline\"\n className={cn(\"relative inline-block whitespace-nowrap\", className)}\n {...props}\n >\n {children}\n <svg\n aria-hidden=\"true\"\n viewBox={SVG_VIEWBOX}\n preserveAspectRatio=\"none\"\n className=\"absolute left-0 right-0 -bottom-1 w-full pointer-events-none\"\n style={{ height: \"0.32em\" }}\n >\n <path\n d={SVG_PATH}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={STROKE_WIDTH}\n strokeLinecap=\"round\"\n style={{\n strokeDasharray: PATH_LENGTH,\n strokeDashoffset: draw ? 0 : PATH_LENGTH,\n transition: reduced\n ? \"none\"\n : `stroke-dashoffset ${duration}ms cubic-bezier(0.22, 1, 0.36, 1)`,\n }}\n />\n </svg>\n </span>\n )\n }\n)\n\nexport { HandUnderline }\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { useReducedMotion } from './chunk-T7EIAVSF.js';
|
|
2
|
+
import { cn } from './chunk-QTH4LSO6.js';
|
|
3
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-2NMEKWO5.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var RotatingWord = React.forwardRef(
|
|
8
|
+
function RotatingWord2(_a, ref) {
|
|
9
|
+
var _b = _a, { words, typingMs = 80, eraseMs = 45, holdMs = 1500, className } = _b, props = __objRest(_b, ["words", "typingMs", "eraseMs", "holdMs", "className"]);
|
|
10
|
+
var _a2;
|
|
11
|
+
const reduced = useReducedMotion();
|
|
12
|
+
const [wordIdx, setWordIdx] = React.useState(0);
|
|
13
|
+
const [chars, setChars] = React.useState(0);
|
|
14
|
+
const [phase, setPhase] = React.useState("typing");
|
|
15
|
+
const current = (_a2 = words[wordIdx]) != null ? _a2 : "";
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (reduced) return;
|
|
18
|
+
let timer;
|
|
19
|
+
if (phase === "typing") {
|
|
20
|
+
if (chars < current.length) {
|
|
21
|
+
timer = window.setTimeout(() => setChars((c) => c + 1), typingMs);
|
|
22
|
+
} else {
|
|
23
|
+
timer = window.setTimeout(() => setPhase("erasing"), holdMs);
|
|
24
|
+
}
|
|
25
|
+
} else if (phase === "erasing") {
|
|
26
|
+
if (chars > 0) {
|
|
27
|
+
timer = window.setTimeout(() => setChars((c) => c - 1), eraseMs);
|
|
28
|
+
} else {
|
|
29
|
+
setWordIdx((i) => (i + 1) % words.length);
|
|
30
|
+
setPhase("typing");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return () => {
|
|
34
|
+
if (timer) window.clearTimeout(timer);
|
|
35
|
+
};
|
|
36
|
+
}, [chars, phase, current, typingMs, eraseMs, holdMs, words.length, reduced]);
|
|
37
|
+
if (reduced) {
|
|
38
|
+
return /* @__PURE__ */ jsx(
|
|
39
|
+
"span",
|
|
40
|
+
__spreadProps(__spreadValues({
|
|
41
|
+
ref,
|
|
42
|
+
"data-slot": "rotating-word",
|
|
43
|
+
className: cn(className),
|
|
44
|
+
"aria-live": "polite"
|
|
45
|
+
}, props), {
|
|
46
|
+
children: words[0]
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const displayed = current.substring(0, chars);
|
|
51
|
+
return /* @__PURE__ */ jsxs(
|
|
52
|
+
"span",
|
|
53
|
+
__spreadProps(__spreadValues({
|
|
54
|
+
ref,
|
|
55
|
+
"data-slot": "rotating-word",
|
|
56
|
+
className: cn("whitespace-nowrap", className),
|
|
57
|
+
"aria-live": "polite",
|
|
58
|
+
"aria-atomic": "true"
|
|
59
|
+
}, props), {
|
|
60
|
+
children: [
|
|
61
|
+
displayed,
|
|
62
|
+
/* @__PURE__ */ jsx(
|
|
63
|
+
"span",
|
|
64
|
+
{
|
|
65
|
+
"aria-hidden": "true",
|
|
66
|
+
className: "cycle-rotating-cursor inline-block align-baseline bg-current ml-[0.05em]",
|
|
67
|
+
style: {
|
|
68
|
+
width: "0.06em",
|
|
69
|
+
height: "0.82em",
|
|
70
|
+
transform: "translateY(0.08em)"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export { RotatingWord };
|
|
81
|
+
//# sourceMappingURL=chunk-JQRGW2RF.js.map
|
|
82
|
+
//# sourceMappingURL=chunk-JQRGW2RF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/effects/rotating-word.tsx"],"names":["RotatingWord","_a"],"mappings":"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","file":"chunk-JQRGW2RF.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\"\n\nexport interface RotatingWordProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Lista de palavras a ciclar (typewriter). */\n words: string[]\n /** Velocidade de digitacao em ms por caractere. Default `80`. */\n typingMs?: number\n /** Velocidade de apagar em ms por caractere. Default `45`. */\n eraseMs?: number\n /** Tempo segurando a palavra completa em ms. Default `1500`. */\n holdMs?: number\n}\n\ntype Phase = \"typing\" | \"holding\" | \"erasing\"\n\n/**\n * Typewriter de palavras em loop. Util em headings de hero para destacar\n * caracteristicas ou propostas de valor que rotacionam.\n *\n * State machine: `typing → holding → erasing → next word`.\n *\n * Cor herda do parent via `currentColor` — wrappa com `text-[color]` ou\n * `text-foreground` no consumer pra controlar. O cursor blink usa a mesma\n * cor do texto (`bg-current`).\n *\n * Acessibilidade:\n * - `aria-live=\"polite\"` + `aria-atomic=\"true\"` — screen reader anuncia a\n * palavra completa apos cada ciclo, sem ler caractere por caractere.\n * - `prefers-reduced-motion: reduce` — renderiza so a primeira palavra,\n * estatica, sem cursor.\n *\n * @example\n * <h1>\n * Aprenda ingles com{\" \"}\n * <RotatingWord\n * className=\"text-[color:var(--brand-default)]\"\n * words={[\"IA\", \"proposito\", \"confianca\"]}\n * />\n * </h1>\n */\nconst RotatingWord = React.forwardRef<HTMLSpanElement, RotatingWordProps>(\n function RotatingWord(\n { words, typingMs = 80, eraseMs = 45, holdMs = 1500, className, ...props },\n ref\n ) {\n const reduced = useReducedMotion()\n const [wordIdx, setWordIdx] = React.useState(0)\n const [chars, setChars] = React.useState(0)\n const [phase, setPhase] = React.useState<Phase>(\"typing\")\n\n const current = words[wordIdx] ?? \"\"\n\n React.useEffect(() => {\n if (reduced) return\n\n let timer: number | undefined\n\n if (phase === \"typing\") {\n if (chars < current.length) {\n timer = window.setTimeout(() => setChars((c) => c + 1), typingMs)\n } else {\n timer = window.setTimeout(() => setPhase(\"erasing\"), holdMs)\n }\n } else if (phase === \"erasing\") {\n if (chars > 0) {\n timer = window.setTimeout(() => setChars((c) => c - 1), eraseMs)\n } else {\n setWordIdx((i) => (i + 1) % words.length)\n setPhase(\"typing\")\n }\n }\n\n return () => {\n if (timer) window.clearTimeout(timer)\n }\n }, [chars, phase, current, typingMs, eraseMs, holdMs, words.length, reduced])\n\n if (reduced) {\n return (\n <span\n ref={ref}\n data-slot=\"rotating-word\"\n className={cn(className)}\n aria-live=\"polite\"\n {...props}\n >\n {words[0]}\n </span>\n )\n }\n\n const displayed = current.substring(0, chars)\n\n return (\n <span\n ref={ref}\n data-slot=\"rotating-word\"\n className={cn(\"whitespace-nowrap\", className)}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n {...props}\n >\n {displayed}\n <span\n aria-hidden=\"true\"\n className=\"cycle-rotating-cursor inline-block align-baseline bg-current ml-[0.05em]\"\n style={{\n width: \"0.06em\",\n height: \"0.82em\",\n transform: \"translateY(0.08em)\",\n }}\n />\n </span>\n )\n }\n)\n\nexport { RotatingWord }\n"]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useReducedMotion } from './chunk-T7EIAVSF.js';
|
|
2
|
+
import { cn } from './chunk-QTH4LSO6.js';
|
|
3
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-2NMEKWO5.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var MagneticButton = React.forwardRef(
|
|
8
|
+
function MagneticButton2(_a, forwardedRef) {
|
|
9
|
+
var _b = _a, { strength = 0.25, radius = 100, className, style, children } = _b, props = __objRest(_b, ["strength", "radius", "className", "style", "children"]);
|
|
10
|
+
const innerRef = React.useRef(null);
|
|
11
|
+
const ref = forwardedRef != null ? forwardedRef : innerRef;
|
|
12
|
+
const hoveredRef = React.useRef(false);
|
|
13
|
+
const reduced = useReducedMotion();
|
|
14
|
+
const [hovered, setHovered] = React.useState(false);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
const el = ref.current;
|
|
17
|
+
if (!el) return;
|
|
18
|
+
const s = hovered ? 1.03 : 1;
|
|
19
|
+
const cur = el.style.transform;
|
|
20
|
+
if (cur && /scale\([^)]+\)/.test(cur)) {
|
|
21
|
+
el.style.transform = cur.replace(/scale\([^)]+\)/, `scale(${s})`);
|
|
22
|
+
} else {
|
|
23
|
+
el.style.transform = `translate3d(0,0,0) scale(${s})`;
|
|
24
|
+
}
|
|
25
|
+
}, [hovered, ref]);
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
if (reduced) return;
|
|
28
|
+
if (typeof window === "undefined") return;
|
|
29
|
+
if (window.matchMedia("(pointer: coarse)").matches) return;
|
|
30
|
+
const el = ref.current;
|
|
31
|
+
if (!el) return;
|
|
32
|
+
let isVisible = false;
|
|
33
|
+
let rafId = 0;
|
|
34
|
+
let lastX = 0;
|
|
35
|
+
let lastY = 0;
|
|
36
|
+
const io = new IntersectionObserver(
|
|
37
|
+
([entry]) => {
|
|
38
|
+
var _a2;
|
|
39
|
+
isVisible = (_a2 = entry == null ? void 0 : entry.isIntersecting) != null ? _a2 : false;
|
|
40
|
+
if (!isVisible) {
|
|
41
|
+
el.style.transform = `translate3d(0,0,0) scale(${hoveredRef.current ? 1.03 : 1})`;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{ rootMargin: "200px" }
|
|
45
|
+
);
|
|
46
|
+
io.observe(el);
|
|
47
|
+
function flush() {
|
|
48
|
+
rafId = 0;
|
|
49
|
+
if (!isVisible) return;
|
|
50
|
+
const cur = ref.current;
|
|
51
|
+
if (!cur) return;
|
|
52
|
+
const rect = cur.getBoundingClientRect();
|
|
53
|
+
const cx = rect.left + rect.width / 2;
|
|
54
|
+
const cy = rect.top + rect.height / 2;
|
|
55
|
+
const dx = lastX - cx;
|
|
56
|
+
const dy = lastY - cy;
|
|
57
|
+
const dist = Math.hypot(dx, dy);
|
|
58
|
+
const tx = dist < radius ? dx * strength : 0;
|
|
59
|
+
const ty = dist < radius ? dy * strength : 0;
|
|
60
|
+
const s = hoveredRef.current ? 1.03 : 1;
|
|
61
|
+
cur.style.transform = `translate3d(${tx}px, ${ty}px, 0) scale(${s})`;
|
|
62
|
+
}
|
|
63
|
+
function onMove(e) {
|
|
64
|
+
if (!isVisible) return;
|
|
65
|
+
lastX = e.clientX;
|
|
66
|
+
lastY = e.clientY;
|
|
67
|
+
if (rafId) return;
|
|
68
|
+
rafId = requestAnimationFrame(flush);
|
|
69
|
+
}
|
|
70
|
+
window.addEventListener("mousemove", onMove, { passive: true });
|
|
71
|
+
return () => {
|
|
72
|
+
window.removeEventListener("mousemove", onMove);
|
|
73
|
+
io.disconnect();
|
|
74
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
75
|
+
};
|
|
76
|
+
}, [reduced, strength, radius, ref]);
|
|
77
|
+
return /* @__PURE__ */ jsx(
|
|
78
|
+
"div",
|
|
79
|
+
__spreadProps(__spreadValues({
|
|
80
|
+
ref,
|
|
81
|
+
"data-slot": "magnetic-button",
|
|
82
|
+
onMouseEnter: () => {
|
|
83
|
+
hoveredRef.current = true;
|
|
84
|
+
setHovered(true);
|
|
85
|
+
},
|
|
86
|
+
onMouseLeave: () => {
|
|
87
|
+
hoveredRef.current = false;
|
|
88
|
+
setHovered(false);
|
|
89
|
+
},
|
|
90
|
+
className: cn("inline-block", className),
|
|
91
|
+
style: __spreadValues({
|
|
92
|
+
transition: "transform 0.25s cubic-bezier(0.22, 1, 0.36, 1)",
|
|
93
|
+
willChange: "transform",
|
|
94
|
+
filter: hovered ? "var(--shadow-brand-glow-hover)" : "var(--shadow-brand-glow-idle)"
|
|
95
|
+
}, style)
|
|
96
|
+
}, props), {
|
|
97
|
+
children
|
|
98
|
+
})
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
export { MagneticButton };
|
|
104
|
+
//# sourceMappingURL=chunk-WCDYTWKA.js.map
|
|
105
|
+
//# sourceMappingURL=chunk-WCDYTWKA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/effects/magnetic-button.tsx"],"names":["MagneticButton","_a"],"mappings":"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","file":"chunk-WCDYTWKA.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\"\n\nexport interface MagneticButtonProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Multiplicador do offset (quanto o filho \"puxa\" em direcao ao cursor). Default `0.25`. */\n strength?: number\n /** Distancia em px na qual o efeito ativa. Default `100`. */\n radius?: number\n children: React.ReactNode\n}\n\n/**\n * Wrapper que aplica efeito magnetico no filho (puxa em direcao ao cursor\n * quando proximo). Inspirado em CTAs premium de landing pages.\n *\n * Otimizacoes de performance:\n * - Escreve `transform` direto no DOM via ref (sem React state na hot path).\n * - Throttle com `requestAnimationFrame` (max 1 update por frame).\n * - `IntersectionObserver` gating: so processa `mousemove` quando visivel\n * (rootMargin 200px pra suavidade na entrada).\n *\n * Acessibilidade:\n * - Skip total se `prefers-reduced-motion: reduce`.\n * - Skip total em `pointer: coarse` (touch devices) — sem cursor real.\n *\n * O drop-shadow usa CSS vars (`--shadow-brand-glow-idle/-hover`) — consumer\n * pode override pro brand proprio sem mexer no componente.\n *\n * @example\n * <MagneticButton>\n * <a href=\"#vendas\">\n * <Button variant=\"default\">CTA principal</Button>\n * </a>\n * </MagneticButton>\n */\nconst MagneticButton = React.forwardRef<HTMLDivElement, MagneticButtonProps>(\n function MagneticButton(\n { strength = 0.25, radius = 100, className, style, children, ...props },\n forwardedRef\n ) {\n const innerRef = React.useRef<HTMLDivElement>(null)\n const ref = (forwardedRef as React.RefObject<HTMLDivElement>) ?? innerRef\n const hoveredRef = React.useRef(false)\n const reduced = useReducedMotion()\n const [hovered, setHovered] = React.useState(false)\n\n // Sincroniza scale quando hover muda — sem tocar no offset do mousemove.\n React.useEffect(() => {\n const el = ref.current\n if (!el) return\n const s = hovered ? 1.03 : 1\n const cur = el.style.transform\n if (cur && /scale\\([^)]+\\)/.test(cur)) {\n el.style.transform = cur.replace(/scale\\([^)]+\\)/, `scale(${s})`)\n } else {\n el.style.transform = `translate3d(0,0,0) scale(${s})`\n }\n }, [hovered, ref])\n\n React.useEffect(() => {\n if (reduced) return\n if (typeof window === \"undefined\") return\n if (window.matchMedia(\"(pointer: coarse)\").matches) return\n\n const el = ref.current\n if (!el) return\n\n let isVisible = false\n let rafId = 0\n let lastX = 0\n let lastY = 0\n\n const io = new IntersectionObserver(\n ([entry]) => {\n isVisible = entry?.isIntersecting ?? false\n if (!isVisible) {\n el.style.transform = `translate3d(0,0,0) scale(${\n hoveredRef.current ? 1.03 : 1\n })`\n }\n },\n { rootMargin: \"200px\" }\n )\n io.observe(el)\n\n function flush() {\n rafId = 0\n if (!isVisible) return\n const cur = ref.current\n if (!cur) return\n const rect = cur.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const dx = lastX - cx\n const dy = lastY - cy\n const dist = Math.hypot(dx, dy)\n const tx = dist < radius ? dx * strength : 0\n const ty = dist < radius ? dy * strength : 0\n const s = hoveredRef.current ? 1.03 : 1\n cur.style.transform = `translate3d(${tx}px, ${ty}px, 0) scale(${s})`\n }\n\n function onMove(e: MouseEvent) {\n if (!isVisible) return\n lastX = e.clientX\n lastY = e.clientY\n if (rafId) return\n rafId = requestAnimationFrame(flush)\n }\n\n window.addEventListener(\"mousemove\", onMove, { passive: true })\n return () => {\n window.removeEventListener(\"mousemove\", onMove)\n io.disconnect()\n if (rafId) cancelAnimationFrame(rafId)\n }\n }, [reduced, strength, radius, ref])\n\n return (\n <div\n ref={ref}\n data-slot=\"magnetic-button\"\n onMouseEnter={() => {\n hoveredRef.current = true\n setHovered(true)\n }}\n onMouseLeave={() => {\n hoveredRef.current = false\n setHovered(false)\n }}\n className={cn(\"inline-block\", className)}\n style={{\n transition: \"transform 0.25s cubic-bezier(0.22, 1, 0.36, 1)\",\n willChange: \"transform\",\n filter: hovered\n ? \"var(--shadow-brand-glow-hover)\"\n : \"var(--shadow-brand-glow-idle)\",\n ...style,\n }}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\n\nexport { MagneticButton }\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { cn } from './chunk-QTH4LSO6.js';
|
|
2
|
+
import { __objRest, __spreadProps, __spreadValues } from './chunk-2NMEKWO5.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var BASE_CLASSES = [
|
|
7
|
+
"text-[color:var(--brand-default)]",
|
|
8
|
+
"hover:text-[color:var(--brand-dark)]",
|
|
9
|
+
"underline-offset-4 transition-colors",
|
|
10
|
+
"outline-none focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
11
|
+
"focus-visible:outline-[color:var(--brand-default)] rounded-sm"
|
|
12
|
+
].join(" ");
|
|
13
|
+
var LinkBrand = React.forwardRef(
|
|
14
|
+
function LinkBrand2(props, ref) {
|
|
15
|
+
if (props.as === "button") {
|
|
16
|
+
const _a = props, { as: _as, className: className2, children: children2 } = _a, rest2 = __objRest(_a, ["as", "className", "children"]);
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
"button",
|
|
19
|
+
__spreadProps(__spreadValues({
|
|
20
|
+
ref,
|
|
21
|
+
type: "button",
|
|
22
|
+
"data-slot": "link-brand",
|
|
23
|
+
className: cn(BASE_CLASSES, className2)
|
|
24
|
+
}, rest2), {
|
|
25
|
+
children: children2
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const _b = props, { href, external = false, className, children } = _b, rest = __objRest(_b, ["href", "external", "className", "children"]);
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
"a",
|
|
32
|
+
__spreadProps(__spreadValues({
|
|
33
|
+
ref,
|
|
34
|
+
href,
|
|
35
|
+
target: external ? "_blank" : void 0,
|
|
36
|
+
rel: external ? "noopener noreferrer" : void 0,
|
|
37
|
+
"data-slot": "link-brand",
|
|
38
|
+
className: cn(BASE_CLASSES, className)
|
|
39
|
+
}, rest), {
|
|
40
|
+
children
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export { LinkBrand };
|
|
47
|
+
//# sourceMappingURL=chunk-YZNOE4TO.js.map
|
|
48
|
+
//# sourceMappingURL=chunk-YZNOE4TO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/marketing/buttons/link-brand.tsx"],"names":["LinkBrand","className","children","rest"],"mappings":";;;;;AAMA,IAAM,YAAA,GAAe;AAAA,EACnB,mCAAA;AAAA,EACA,sCAAA;AAAA,EACA,sCAAA;AAAA,EACA,qEAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,GAAG,CAAA;AAuCV,IAAM,SAAA,GAAkB,KAAA,CAAA,UAAA;AAAA,EACtB,SAASA,UAAAA,CAAU,KAAA,EAAO,GAAA,EAAK;AAC7B,IAAA,IAAI,KAAA,CAAM,OAAO,QAAA,EAAU;AACzB,MAAA,MAAkD,EAAA,GAAA,KAAA,EAA1C,EAAA,EAAA,EAAI,GAAA,EAAK,SAAA,EAAAC,YAAW,QAAA,EAAAC,SAAAA,EAtDlC,GAsDwD,EAAA,EAATC,KAAAA,GAAA,SAAA,CAAS,EAAA,EAAT,CAAjC,MAAS,WAAA,EAAW,UAAA,CAAA,CAAA;AAC5B,MAAA,uBACE,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA,aAAA,CAAA,cAAA,CAAA;AAAA,UACC,GAAA;AAAA,UACA,IAAA,EAAK,QAAA;AAAA,UACL,WAAA,EAAU,YAAA;AAAA,UACV,SAAA,EAAW,EAAA,CAAG,YAAA,EAAcF,UAAS;AAAA,SAAA,EACjCE,KAAAA,CAAAA,EALL;AAAA,UAOE,QAAA,EAAAD;AAAA,SAAA;AAAA,OACH;AAAA,IAEJ;AAEA,IAAA,MAAiE,EAAA,GAAA,KAAA,EAAzD,EAAA,IAAA,EAAM,QAAA,GAAW,KAAA,EAAO,SAAA,EAAW,QAAA,EApE/C,GAoEqE,EAAA,EAAT,IAAA,GAAA,SAAA,CAAS,EAAA,EAAT,CAAhD,MAAA,EAAM,YAAkB,WAAA,EAAW,UAAA,CAAA,CAAA;AAC3C,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA,aAAA,CAAA,cAAA,CAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAA,EAAQ,WAAW,QAAA,GAAW,MAAA;AAAA,QAC9B,GAAA,EAAK,WAAW,qBAAA,GAAwB,MAAA;AAAA,QACxC,WAAA,EAAU,YAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,YAAA,EAAc,SAAS;AAAA,OAAA,EACjC,IAAA,CAAA,EAPL;AAAA,QASE;AAAA,OAAA;AAAA,KACH;AAAA,EAEJ;AACF","file":"chunk-YZNOE4TO.js","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst BASE_CLASSES = [\n \"text-[color:var(--brand-default)]\",\n \"hover:text-[color:var(--brand-dark)]\",\n \"underline-offset-4 transition-colors\",\n \"outline-none focus-visible:outline-2 focus-visible:outline-offset-2\",\n \"focus-visible:outline-[color:var(--brand-default)] rounded-sm\",\n].join(\" \")\n\ntype LinkBrandAnchorProps = {\n /** Renderiza como `<a>` (default). */\n as?: \"a\"\n /** URL destino. */\n href: string\n external?: boolean\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, \"as\" | \"href\">\n\ntype LinkBrandButtonProps = {\n /** Renderiza como `<button>` quando a acao e JS (sem URL). */\n as: \"button\"\n href?: never\n external?: never\n} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"as\">\n\nexport type LinkBrandProps = LinkBrandAnchorProps | LinkBrandButtonProps\n\n/**\n * Link de texto discreto da marca — `text-brand-default` com hover pra\n * `text-brand-dark`. Usado em nav, footer e texto inline.\n *\n * Sem underline por default (visual mais clean). Pra ter underline, passe\n * `className=\"hover:underline\"` ou `underline` no consumer.\n *\n * Pode renderizar como `<a>` (default) ou `<button>` via prop `as`.\n *\n * @example\n * <LinkBrand href=\"/precos\">Ver planos</LinkBrand>\n *\n * <LinkBrand href=\"https://twitter.com\" external>\n * Siga no Twitter\n * </LinkBrand>\n *\n * <LinkBrand as=\"button\" onClick={() => openModal()}>\n * Abrir filtros\n * </LinkBrand>\n */\nconst LinkBrand = React.forwardRef<HTMLAnchorElement | HTMLButtonElement, LinkBrandProps>(\n function LinkBrand(props, ref) {\n if (props.as === \"button\") {\n const { as: _as, className, children, ...rest } = props\n return (\n <button\n ref={ref as React.Ref<HTMLButtonElement>}\n type=\"button\"\n data-slot=\"link-brand\"\n className={cn(BASE_CLASSES, className)}\n {...rest}\n >\n {children}\n </button>\n )\n }\n\n const { href, external = false, className, children, ...rest } = props\n return (\n <a\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n target={external ? \"_blank\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n data-slot=\"link-brand\"\n className={cn(BASE_CLASSES, className)}\n {...rest}\n >\n {children}\n </a>\n )\n }\n)\n\nexport { LinkBrand }\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
declare const ctaBrandVariants: (props?: ({
|
|
6
|
+
size?: "md" | "lg" | null | undefined;
|
|
7
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
|
+
interface CtaBrandProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "size">, VariantProps<typeof ctaBrandVariants> {
|
|
9
|
+
/** URL destino. Sempre renderiza como `<a>`. Pra acao de JS sem URL, use `<Button>` core. */
|
|
10
|
+
href: string;
|
|
11
|
+
/** Quando true, abre em nova aba com `rel="noopener noreferrer"`. Default `false`. */
|
|
12
|
+
external?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Escape hatch — desliga o efeito magnetic wrapper. Use em contextos onde o
|
|
15
|
+
* movimento incomoda (dentro de Sheet/Drawer/popover). Default `false`
|
|
16
|
+
* (magnetic SEMPRE ligado — esse e o ponto do CtaBrand).
|
|
17
|
+
*/
|
|
18
|
+
disableMagnetic?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* CTA principal de marketing — botao com gradient brand rose (Fluencypass),
|
|
22
|
+
* rounded-full, drop-shadow glow + brightness hover, e efeito magnetic
|
|
23
|
+
* embutido (puxa em direcao ao cursor).
|
|
24
|
+
*
|
|
25
|
+
* Pra acoes de JS sem URL (submit de form, abrir modal etc), use o
|
|
26
|
+
* `<Button>` core do Cycle em vez disso.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* <CtaBrand href="#vendas">
|
|
30
|
+
* Solicitar demonstracao
|
|
31
|
+
* </CtaBrand>
|
|
32
|
+
*
|
|
33
|
+
* <CtaBrand href="https://app.fluencypass.com" external size="md">
|
|
34
|
+
* Acessar app
|
|
35
|
+
* </CtaBrand>
|
|
36
|
+
*/
|
|
37
|
+
declare const CtaBrand: React.ForwardRefExoticComponent<CtaBrandProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
38
|
+
|
|
39
|
+
export { CtaBrand, type CtaBrandProps, ctaBrandVariants };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export { CtaBrand, ctaBrandVariants } from '../../chunk-DJ3DMPKK.js';
|
|
3
|
+
import '../../chunk-WCDYTWKA.js';
|
|
4
|
+
import '../../chunk-T7EIAVSF.js';
|
|
5
|
+
import '../../chunk-QTH4LSO6.js';
|
|
6
|
+
import '../../chunk-2NMEKWO5.js';
|
|
7
|
+
//# sourceMappingURL=cta-brand.js.map
|
|
8
|
+
//# sourceMappingURL=cta-brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"cta-brand.js"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export { CtaBrand, ctaBrandVariants } from '../../chunk-DJ3DMPKK.js';
|
|
3
|
+
export { LinkBrand } from '../../chunk-YZNOE4TO.js';
|
|
4
|
+
import '../../chunk-WCDYTWKA.js';
|
|
5
|
+
import '../../chunk-T7EIAVSF.js';
|
|
6
|
+
import '../../chunk-QTH4LSO6.js';
|
|
7
|
+
import '../../chunk-2NMEKWO5.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type LinkBrandAnchorProps = {
|
|
4
|
+
/** Renderiza como `<a>` (default). */
|
|
5
|
+
as?: "a";
|
|
6
|
+
/** URL destino. */
|
|
7
|
+
href: string;
|
|
8
|
+
external?: boolean;
|
|
9
|
+
} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "as" | "href">;
|
|
10
|
+
type LinkBrandButtonProps = {
|
|
11
|
+
/** Renderiza como `<button>` quando a acao e JS (sem URL). */
|
|
12
|
+
as: "button";
|
|
13
|
+
href?: never;
|
|
14
|
+
external?: never;
|
|
15
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "as">;
|
|
16
|
+
type LinkBrandProps = LinkBrandAnchorProps | LinkBrandButtonProps;
|
|
17
|
+
/**
|
|
18
|
+
* Link de texto discreto da marca — `text-brand-default` com hover pra
|
|
19
|
+
* `text-brand-dark`. Usado em nav, footer e texto inline.
|
|
20
|
+
*
|
|
21
|
+
* Sem underline por default (visual mais clean). Pra ter underline, passe
|
|
22
|
+
* `className="hover:underline"` ou `underline` no consumer.
|
|
23
|
+
*
|
|
24
|
+
* Pode renderizar como `<a>` (default) ou `<button>` via prop `as`.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* <LinkBrand href="/precos">Ver planos</LinkBrand>
|
|
28
|
+
*
|
|
29
|
+
* <LinkBrand href="https://twitter.com" external>
|
|
30
|
+
* Siga no Twitter
|
|
31
|
+
* </LinkBrand>
|
|
32
|
+
*
|
|
33
|
+
* <LinkBrand as="button" onClick={() => openModal()}>
|
|
34
|
+
* Abrir filtros
|
|
35
|
+
* </LinkBrand>
|
|
36
|
+
*/
|
|
37
|
+
declare const LinkBrand: React.ForwardRefExoticComponent<LinkBrandProps & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
|
|
38
|
+
|
|
39
|
+
export { LinkBrand, type LinkBrandProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"link-brand.js"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface HandUnderlineProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
4
|
+
/** Delay em ms entre intersecao no viewport e inicio do draw. Default `600`. */
|
|
5
|
+
delay?: number;
|
|
6
|
+
/** Duracao do draw em ms (stroke-dashoffset 240 → 0). Default `780`. */
|
|
7
|
+
duration?: number;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Wrapper que desenha um underline SVG em curva sutil abaixo do texto, animado
|
|
12
|
+
* via stroke-dasharray quando entra no viewport. Util pra dar enfase em
|
|
13
|
+
* palavras-chave em headings sem usar bold/color.
|
|
14
|
+
*
|
|
15
|
+
* Cor do stroke: `currentColor` — herda do parent. Wrappa com
|
|
16
|
+
* `<span className="text-[color:var(--brand-default)]">` ou outra cor.
|
|
17
|
+
*
|
|
18
|
+
* Acessibilidade:
|
|
19
|
+
* - SVG `aria-hidden` (decorativo).
|
|
20
|
+
* - `prefers-reduced-motion: reduce` — desenha o underline completo direto,
|
|
21
|
+
* sem animar.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <h2>
|
|
25
|
+
* Acelere o ingles do seu{" "}
|
|
26
|
+
* <HandUnderline className="text-[color:var(--brand-default)]">
|
|
27
|
+
* time corporativo
|
|
28
|
+
* </HandUnderline>
|
|
29
|
+
* </h2>
|
|
30
|
+
*/
|
|
31
|
+
declare const HandUnderline: React.ForwardRefExoticComponent<HandUnderlineProps & React.RefAttributes<HTMLSpanElement>>;
|
|
32
|
+
|
|
33
|
+
export { HandUnderline, type HandUnderlineProps };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export { HandUnderline } from '../../chunk-G57PPNB3.js';
|
|
3
|
+
import '../../chunk-T7EIAVSF.js';
|
|
4
|
+
import '../../chunk-OHRYR7PN.js';
|
|
5
|
+
import '../../chunk-QTH4LSO6.js';
|
|
6
|
+
import '../../chunk-2NMEKWO5.js';
|
|
7
|
+
//# sourceMappingURL=hand-underline.js.map
|
|
8
|
+
//# sourceMappingURL=hand-underline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"hand-underline.js"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { CircleGlow, CircleGlowProps } from './circle-glow.js';
|
|
2
2
|
export { CardDarkGlow, CardDarkGlowProps } from './card-dark-glow.js';
|
|
3
3
|
export { Marquee, MarqueeProps } from './marquee.js';
|
|
4
|
+
export { MagneticButton, MagneticButtonProps } from './magnetic-button.js';
|
|
5
|
+
export { RotatingWord, RotatingWordProps } from './rotating-word.js';
|
|
6
|
+
export { HandUnderline, HandUnderlineProps } from './hand-underline.js';
|
|
4
7
|
import 'react';
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
export { RotatingWord } from '../../chunk-JQRGW2RF.js';
|
|
3
|
+
export { HandUnderline } from '../../chunk-G57PPNB3.js';
|
|
4
|
+
export { MagneticButton } from '../../chunk-WCDYTWKA.js';
|
|
2
5
|
export { CircleGlow } from '../../chunk-U27GHP5Z.js';
|
|
3
6
|
export { CardDarkGlow } from '../../chunk-K2XIXOMO.js';
|
|
4
7
|
export { Marquee } from '../../chunk-HXFGULDU.js';
|
|
8
|
+
import '../../chunk-T7EIAVSF.js';
|
|
9
|
+
import '../../chunk-OHRYR7PN.js';
|
|
5
10
|
import '../../chunk-QTH4LSO6.js';
|
|
6
11
|
import '../../chunk-2NMEKWO5.js';
|
|
7
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface MagneticButtonProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
4
|
+
/** Multiplicador do offset (quanto o filho "puxa" em direcao ao cursor). Default `0.25`. */
|
|
5
|
+
strength?: number;
|
|
6
|
+
/** Distancia em px na qual o efeito ativa. Default `100`. */
|
|
7
|
+
radius?: number;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Wrapper que aplica efeito magnetico no filho (puxa em direcao ao cursor
|
|
12
|
+
* quando proximo). Inspirado em CTAs premium de landing pages.
|
|
13
|
+
*
|
|
14
|
+
* Otimizacoes de performance:
|
|
15
|
+
* - Escreve `transform` direto no DOM via ref (sem React state na hot path).
|
|
16
|
+
* - Throttle com `requestAnimationFrame` (max 1 update por frame).
|
|
17
|
+
* - `IntersectionObserver` gating: so processa `mousemove` quando visivel
|
|
18
|
+
* (rootMargin 200px pra suavidade na entrada).
|
|
19
|
+
*
|
|
20
|
+
* Acessibilidade:
|
|
21
|
+
* - Skip total se `prefers-reduced-motion: reduce`.
|
|
22
|
+
* - Skip total em `pointer: coarse` (touch devices) — sem cursor real.
|
|
23
|
+
*
|
|
24
|
+
* O drop-shadow usa CSS vars (`--shadow-brand-glow-idle/-hover`) — consumer
|
|
25
|
+
* pode override pro brand proprio sem mexer no componente.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* <MagneticButton>
|
|
29
|
+
* <a href="#vendas">
|
|
30
|
+
* <Button variant="default">CTA principal</Button>
|
|
31
|
+
* </a>
|
|
32
|
+
* </MagneticButton>
|
|
33
|
+
*/
|
|
34
|
+
declare const MagneticButton: React.ForwardRefExoticComponent<MagneticButtonProps & React.RefAttributes<HTMLDivElement>>;
|
|
35
|
+
|
|
36
|
+
export { MagneticButton, type MagneticButtonProps };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
export { MagneticButton } from '../../chunk-WCDYTWKA.js';
|
|
3
|
+
import '../../chunk-T7EIAVSF.js';
|
|
4
|
+
import '../../chunk-QTH4LSO6.js';
|
|
5
|
+
import '../../chunk-2NMEKWO5.js';
|
|
6
|
+
//# sourceMappingURL=magnetic-button.js.map
|
|
7
|
+
//# sourceMappingURL=magnetic-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"magnetic-button.js"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface RotatingWordProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
4
|
+
/** Lista de palavras a ciclar (typewriter). */
|
|
5
|
+
words: string[];
|
|
6
|
+
/** Velocidade de digitacao em ms por caractere. Default `80`. */
|
|
7
|
+
typingMs?: number;
|
|
8
|
+
/** Velocidade de apagar em ms por caractere. Default `45`. */
|
|
9
|
+
eraseMs?: number;
|
|
10
|
+
/** Tempo segurando a palavra completa em ms. Default `1500`. */
|
|
11
|
+
holdMs?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Typewriter de palavras em loop. Util em headings de hero para destacar
|
|
15
|
+
* caracteristicas ou propostas de valor que rotacionam.
|
|
16
|
+
*
|
|
17
|
+
* State machine: `typing → holding → erasing → next word`.
|
|
18
|
+
*
|
|
19
|
+
* Cor herda do parent via `currentColor` — wrappa com `text-[color]` ou
|
|
20
|
+
* `text-foreground` no consumer pra controlar. O cursor blink usa a mesma
|
|
21
|
+
* cor do texto (`bg-current`).
|
|
22
|
+
*
|
|
23
|
+
* Acessibilidade:
|
|
24
|
+
* - `aria-live="polite"` + `aria-atomic="true"` — screen reader anuncia a
|
|
25
|
+
* palavra completa apos cada ciclo, sem ler caractere por caractere.
|
|
26
|
+
* - `prefers-reduced-motion: reduce` — renderiza so a primeira palavra,
|
|
27
|
+
* estatica, sem cursor.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* <h1>
|
|
31
|
+
* Aprenda ingles com{" "}
|
|
32
|
+
* <RotatingWord
|
|
33
|
+
* className="text-[color:var(--brand-default)]"
|
|
34
|
+
* words={["IA", "proposito", "confianca"]}
|
|
35
|
+
* />
|
|
36
|
+
* </h1>
|
|
37
|
+
*/
|
|
38
|
+
declare const RotatingWord: React.ForwardRefExoticComponent<RotatingWordProps & React.RefAttributes<HTMLSpanElement>>;
|
|
39
|
+
|
|
40
|
+
export { RotatingWord, type RotatingWordProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"rotating-word.js"}
|
package/dist/styles/tokens.css
CHANGED
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
--color-neutral-input: var(--neutral-input);
|
|
60
60
|
--color-neutral-bg: var(--neutral-bg);
|
|
61
61
|
--color-neutral-accent: var(--neutral-accent);
|
|
62
|
+
--color-neutral-ring: var(--neutral-ring);
|
|
62
63
|
--radius-sm: calc(var(--radius) - 4px);
|
|
63
64
|
--radius-md: calc(var(--radius) - 2px);
|
|
64
65
|
--radius-lg: var(--radius);
|
|
@@ -139,6 +140,7 @@
|
|
|
139
140
|
--neutral-input: var(--gray-200);
|
|
140
141
|
--neutral-bg: var(--base-white);
|
|
141
142
|
--neutral-accent: var(--gray-100);
|
|
143
|
+
--neutral-ring: var(--gray-500);
|
|
142
144
|
--alpha-backdrop: rgba(0, 0, 0, 0.6);
|
|
143
145
|
--alpha-overlay: rgba(255, 255, 255, 0.6);
|
|
144
146
|
|
|
@@ -191,6 +193,7 @@
|
|
|
191
193
|
--neutral-input: var(--gray-800);
|
|
192
194
|
--neutral-bg: var(--gray-950);
|
|
193
195
|
--neutral-accent: var(--gray-800);
|
|
196
|
+
--neutral-ring: var(--gray-500);
|
|
194
197
|
--alpha-backdrop: rgba(0, 0, 0, 0.6);
|
|
195
198
|
--alpha-overlay: rgba(255, 255, 255, 0.6);
|
|
196
199
|
|
|
@@ -222,7 +225,7 @@
|
|
|
222
225
|
--popover-foreground: #D45558;
|
|
223
226
|
--muted: #FFD0D1;
|
|
224
227
|
--muted-foreground: #8C2D2F;
|
|
225
|
-
--accent: #
|
|
228
|
+
--accent: #FFE8E8;
|
|
226
229
|
--accent-foreground: #6B1E20;
|
|
227
230
|
--primary: #D45558;
|
|
228
231
|
--primary-foreground: #FFFFFF;
|
|
@@ -242,7 +245,7 @@
|
|
|
242
245
|
--popover-foreground: #1A5FE0;
|
|
243
246
|
--muted: #C2D6FF;
|
|
244
247
|
--muted-foreground: #0A3590;
|
|
245
|
-
--accent: #
|
|
248
|
+
--accent: #E0EBFF;
|
|
246
249
|
--accent-foreground: #062268;
|
|
247
250
|
--primary: #1A5FE0;
|
|
248
251
|
--primary-foreground: #FFFFFF;
|
|
@@ -262,7 +265,7 @@
|
|
|
262
265
|
--popover-foreground: #E56530;
|
|
263
266
|
--muted: #FFD9C2;
|
|
264
267
|
--muted-foreground: #993A16;
|
|
265
|
-
--accent: #
|
|
268
|
+
--accent: #FFEDE0;
|
|
266
269
|
--accent-foreground: #73270E;
|
|
267
270
|
--primary: #E56530;
|
|
268
271
|
--primary-foreground: #FFFFFF;
|
|
@@ -282,7 +285,7 @@
|
|
|
282
285
|
--popover-foreground: #00C234;
|
|
283
286
|
--muted: #B8FFD0;
|
|
284
287
|
--muted-foreground: #00731E;
|
|
285
|
-
--accent: #
|
|
288
|
+
--accent: #E0FFE9;
|
|
286
289
|
--accent-foreground: #004D14;
|
|
287
290
|
--primary: #00C234;
|
|
288
291
|
--primary-foreground: #0a0a0a;
|
|
@@ -302,7 +305,7 @@
|
|
|
302
305
|
--popover-foreground: #7D0DD4;
|
|
303
306
|
--muted: #EFC2FF;
|
|
304
307
|
--muted-foreground: #48077C;
|
|
305
|
-
--accent: #
|
|
308
|
+
--accent: #F7E0FF;
|
|
306
309
|
--accent-foreground: #48077C;
|
|
307
310
|
--primary: #7D0DD4;
|
|
308
311
|
--primary-foreground: #FFFFFF;
|
|
@@ -322,7 +325,7 @@
|
|
|
322
325
|
--popover-foreground: #098A5E;
|
|
323
326
|
--muted: #B8F2D9;
|
|
324
327
|
--muted-foreground: #05523A;
|
|
325
|
-
--accent: #
|
|
328
|
+
--accent: #E0FAF0;
|
|
326
329
|
--accent-foreground: #033526;
|
|
327
330
|
--primary: #098A5E;
|
|
328
331
|
--primary-foreground: #FFFFFF;
|
|
@@ -342,7 +345,7 @@
|
|
|
342
345
|
--popover-foreground: #D48E00;
|
|
343
346
|
--muted: #FEEAB0;
|
|
344
347
|
--muted-foreground: #7D5400;
|
|
345
|
-
--accent: #
|
|
348
|
+
--accent: #FFF5D9;
|
|
346
349
|
--accent-foreground: #523800;
|
|
347
350
|
--primary: #D48E00;
|
|
348
351
|
--primary-foreground: #FFFFFF;
|
|
@@ -362,7 +365,7 @@
|
|
|
362
365
|
--popover-foreground: #B32020;
|
|
363
366
|
--muted: #FFD0D0;
|
|
364
367
|
--muted-foreground: #6B1010;
|
|
365
|
-
--accent: #
|
|
368
|
+
--accent: #FFE8E8;
|
|
366
369
|
--accent-foreground: #470A0A;
|
|
367
370
|
--primary: #B32020;
|
|
368
371
|
--primary-foreground: #FFFFFF;
|
|
@@ -1039,6 +1042,32 @@
|
|
|
1039
1042
|
.cycle-marquee-track { animation: none; }
|
|
1040
1043
|
}
|
|
1041
1044
|
|
|
1045
|
+
/* ============================================================
|
|
1046
|
+
Cycle Marketing — Camada 2b (Buttons + Motion avançado)
|
|
1047
|
+
Replicado de globals.css para o CSS distribuido (styles.css).
|
|
1048
|
+
============================================================ */
|
|
1049
|
+
|
|
1050
|
+
:root {
|
|
1051
|
+
--shadow-brand-glow-idle: drop-shadow(0 4px 8px rgba(237, 106, 109, 0.15));
|
|
1052
|
+
--shadow-brand-glow-hover: drop-shadow(0 12px 24px rgba(237, 106, 109, 0.35));
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
@keyframes cycle-rotating-cursor-blink {
|
|
1056
|
+
0%, 49% { opacity: 1; }
|
|
1057
|
+
50%, 100% { opacity: 0; }
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.cycle-rotating-cursor {
|
|
1061
|
+
animation: cycle-rotating-cursor-blink 1s steps(2, end) infinite;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1065
|
+
.cycle-rotating-cursor {
|
|
1066
|
+
opacity: 0;
|
|
1067
|
+
animation: none;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1042
1071
|
@media (pointer: fine) {
|
|
1043
1072
|
[data-media-player][data-layout='video']:not([data-fullscreen]) {
|
|
1044
1073
|
border-radius: 16px !important;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluencypassdevs/cycle",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.1",
|
|
4
4
|
"description": "Cycle Design System — UI component library by Fluencypass",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -83,6 +83,14 @@
|
|
|
83
83
|
"import": "./dist/marketing/effects/*.js",
|
|
84
84
|
"types": "./dist/marketing/effects/*.d.ts"
|
|
85
85
|
},
|
|
86
|
+
"./marketing/buttons": {
|
|
87
|
+
"import": "./dist/marketing/buttons/index.js",
|
|
88
|
+
"types": "./dist/marketing/buttons/index.d.ts"
|
|
89
|
+
},
|
|
90
|
+
"./marketing/buttons/*": {
|
|
91
|
+
"import": "./dist/marketing/buttons/*.js",
|
|
92
|
+
"types": "./dist/marketing/buttons/*.d.ts"
|
|
93
|
+
},
|
|
86
94
|
"./styles.css": "./dist/styles/tokens.css",
|
|
87
95
|
"./tailwind-theme.css": "./dist/styles/tokens.css"
|
|
88
96
|
},
|