// components.jsx — shared primitives for Butter Cream Doces const { useState, useEffect, useRef } = React; const WA_NUMBER = "5562994198503"; function waLink(msg) { const text = encodeURIComponent(msg || "Olá! Gostaria de solicitar um orçamento de doces para meu evento."); return `https://wa.me/${WA_NUMBER}?text=${text}`; } /* ---------- Icons (stroke, 24x24) ---------- */ const Icon = { whatsapp: (p) => ( ), arrow: (p) => (), plus: (p) => (), star: (p) => (), craft: (p) => (), leaf: (p) => (), heart: (p) => (), box: (p) => (), chat: (p) => (), taste: (p) => (), brush: (p) => (), truck: (p) => (), pin: (p) => (), mail: (p) => (), ig: (p) => (), menu: (p) => (), cake: (p) => (), }; /* ---------- WhatsApp Button ---------- */ function WaButton({ msg, children, className = "btn-primary", size = "" }) { return ( {children} ); } /* ---------- Image Placeholder ---------- */ function Ph({ label, dark = false, icon = true, style }) { return (
{icon && } {label}
); } /* ---------- Scroll reveal (survives React re-renders) ---------- */ function useReveal() { // Re-assert revealed state synchronously before paint so a React re-render // (which rewrites className from JSX) can't wipe the imperatively-added "in". React.useLayoutEffect(() => { if (window.__revealed) window.__revealed.forEach((el) => { if (el.isConnected) el.classList.add("in"); }); }); useEffect(() => { if (!window.__revealed) window.__revealed = new Set(); let io = window.__bcIO; if (!io) { io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); window.__revealed.add(e.target); } }); }, { threshold: 0.08, rootMargin: "0px 0px -6% 0px" }); window.__bcIO = io; } document.querySelectorAll(".reveal").forEach((el) => io.observe(el)); // safety: if frames never run (throttled/background tab), snap content visible // without a transition so it can never get stuck at opacity 0. const safety = setTimeout(() => { document.querySelectorAll(".reveal:not(.in)").forEach((el) => { if (el.getBoundingClientRect().top < window.innerHeight * 1.05) { el.style.transition = "none"; el.classList.add("in"); window.__revealed.add(el); } }); }, 600); return () => clearTimeout(safety); }); } /* ---------- Section eyebrow + heading ---------- */ function SecHead({ eyebrow, title, lead, align = "center" }) { return (

{eyebrow}

{title}

{lead &&

{lead}

}
); } Object.assign(window, { WA_NUMBER, waLink, Icon, WaButton, Ph, useReveal, SecHead });