/* ========================================================= Dr. Boechat — Shared form components (React, Babel) Exposes components on window for the three form apps. ========================================================= */ const { useState, useRef, useEffect, useCallback } = React; /* ---------------- Masks ---------------- */ const onlyDigits = (s) => (s || "").replace(/\D/g, ""); const maskCPF = (v) => { const d = onlyDigits(v).slice(0, 11); return d .replace(/(\d{3})(\d)/, "$1.$2") .replace(/(\d{3})(\d)/, "$1.$2") .replace(/(\d{3})(\d{1,2})$/, "$1-$2"); }; const maskPhone = (v) => { const d = onlyDigits(v).slice(0, 11); if (d.length <= 10) return d.replace(/(\d{2})(\d)/, "($1) $2").replace(/(\d{4})(\d)/, "$1-$2"); return d.replace(/(\d{2})(\d)/, "($1) $2").replace(/(\d{5})(\d)/, "$1-$2"); }; const maskCEP = (v) => onlyDigits(v).slice(0, 8).replace(/(\d{5})(\d)/, "$1-$2"); const maskDate = (v) => { const d = onlyDigits(v).slice(0, 8); return d.replace(/(\d{2})(\d)/, "$1/$2").replace(/(\d{2})(\d)/, "$1/$2"); }; const MASKS = { cpf: maskCPF, phone: maskPhone, cep: maskCEP, date: maskDate }; /* ---------------- Validators ---------------- */ const isCPFComplete = (v) => onlyDigits(v).length === 11; const isEmail = (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim()); const isPhoneComplete = (v) => onlyDigits(v).length >= 10; const isDateComplete = (v) => onlyDigits(v).length === 8; /* ---------------- Icons ---------------- */ const Ico = { back: , alert: , arrowR: , arrowL: , check: , send: , eraser: , }; const Svg = ({ d, w = 18, sw = 1.8, fill = "none" }) => ( {d} ); /* ---------------- AppTop ---------------- */ function AppTop({ logo = "../assets/logo-purple.png" }) { return (
Dr. Boechat Início
); } /* ---------------- Field wrapper ---------------- */ function Field({ label, required, error, hint, full, children }) { return (
{label && ( )} {children} {error ? ( {error} ) : hint ? ( {hint} ) : null}
); } /* ---------------- TextField (with optional mask) ---------------- */ function TextField({ label, value, onChange, mask, type = "text", required, error, hint, placeholder, full, inputMode, maxLength, }) { const filled = value && String(value).length > 0 && !error; const handle = (e) => { let v = e.target.value; if (mask && MASKS[mask]) v = MASKS[mask](v); onChange(v); }; return (
{label && } {error ? ( {error} ) : hint ? ({hint}) : null}
); } /* ---------------- SelectField ---------------- */ function SelectField({ label, value, onChange, options, required, error, hint, full, placeholder = "Selecione…" }) { const filled = value && value.length > 0 && !error; return (
{label && } {error ? ( {error} ) : hint ? ({hint}) : null}
); } /* ---------------- TextArea ---------------- */ function TextArea({ label, value, onChange, required, error, hint, placeholder, rows }) { const filled = value && value.length > 0; return (
{label && }