UNPKG

isa-bubbles

Version:

Tiny, dependency-free JavaScript widgets that add interactive “bubbles” to any website — such as credits, contact forms, or feedback prompts.

255 lines (232 loc) 7.61 kB
export default class ContactBubble { constructor({ textCollapsed = "✉️", textExpanded = "send feedback ✉️", parent = document.body, onSubmit = () => { alert("click on submitted"); }, // position position = "fixed", right = "85px", left = "None", top = "None", bottom = "20px", // colors colorCollapsed = "#fff", colorExpanded = "#fff", backgroundColorCollapsed = "rgba(63, 178, 124, 0.75)", backgroundColorExpanded = "rgba(63, 178, 124, 0.65)", // sizing fontSizeCollapsed = "20px", fontSizeExpanded = "15px", heightCollapsed = "30px", widthCollapsed = "30px", heightExpanded = "50px", widthExpanded = "50px", lineHeightCollapsed = "1", lineHeightExpanded = "1", // padding collapsed paddingLeftCollapsed = "4px", paddingRightCollapsed = "0px", paddingTopCollapsed = "0px", paddingBottomCollapsed = "0px", // padding expanded paddingLeftExpanded = "7px", paddingRightExpanded = "11px", paddingTopExpanded = "8px", paddingBottomExpanded = "8px", //form formPosition = "fixed", formPositionRight = "2rem", formPositionLeft = "None", formPositionTop = "None", formPositionBottom = "100px", zIndex = "5", }) { this.textCollapsed = textCollapsed; this.textExpanded = textExpanded; this.collapsed = true; this.showForm = false; this.onSubmit = onSubmit; // Inject styles if (!document.getElementById("contact-bubble-styles")) { const style = document.createElement("style"); style.id = "contact-bubble-styles"; style.textContent = ` .contact-container { width: 100%; } .contact-bubble { position: ${position}; right: ${right}; bottom: ${bottom}; left: ${left}; top: ${top}; color: ${colorCollapsed}; height: ${heightCollapsed}; width: ${widthCollapsed}; padding-left: ${paddingLeftCollapsed}; padding-right: ${paddingRightCollapsed}; padding-top: ${paddingTopCollapsed}; padding-bottom: ${paddingBottomCollapsed}; background-color: ${backgroundColorCollapsed}; font-size: ${fontSizeCollapsed}; line-height: ${lineHeightCollapsed}; z-index: ${zIndex}; display: flex; place-items: center; overflow: hidden; cursor: pointer; transition: all 1s ease; border-radius: 50%; } .bubble-contact-text{ background-color: ${backgroundColorExpanded}; color: ${colorExpanded}; font-size: ${fontSizeExpanded}; height: ${heightExpanded}; width: ${widthExpanded}; padding-left: ${paddingLeftExpanded}; padding-right: ${paddingRightExpanded}; padding-top: ${paddingTopExpanded}; padding-bottom: ${paddingBottomExpanded}; line-height: ${lineHeightExpanded}; z-index: ${zIndex}; text-align: center; transition: all 1s ease; display: flex; place-items: center; border-radius: 50%; } .contact-form { font-size: 0.9rem; padding: 5%; position: ${formPosition}; bottom: ${formPositionBottom}; right: ${formPositionRight}; left: ${formPositionLeft}; top: ${formPositionTop}; background: white; border-radius: 16px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); padding: 20px; color: rgba(103, 111, 107, 0.85); width: 250px; animation: floatUp 1s ease forwards; /* changed from popIn */ z-index: 1000; } @keyframes floatUp { 0% { transform: translateY(50px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } } .contact-form h4 { margin-top: 0; color: #0b440e; text-align: center; } .contact-form input, .contact-form textarea { width: 90%; margin-top: 0.5rem; padding: 0.5rem; border-radius: 8px; border: 1px solid #ccc; font-size: 0.9rem; } .contact-form button { background-color: rgba(63, 178, 124, 0.75); color: white; border: none; border-radius: 8px; padding: 0.6rem; margin-top: 0.8rem; width: 100%; cursor: pointer; font-weight: 600; transition: transform 0.2s ease; } .contact-form button:hover { transform: scale(1.02); background-color: rgba(63, 178, 124, 0.95); } .close-btn { position: absolute; top: 10px; right: 25px; font-size: 1.2rem; font-weight: 600; color: rgba(63, 178, 124, 0.75); background: none; border: none; cursor: pointer; transition: transform 0.2s ease, color 0.2s ease; } .close-btn:hover { transform: scale(1.2); color: rgba(63, 178, 124, 0.95); /* darker hover green */ }`; document.head.appendChild(style); } // Container this.container = document.createElement("div"); this.container.className = "contact-container"; // Bubble this.bubble = document.createElement("div"); this.bubble.className = "contact-bubble"; this.bubble.textContent = this.textCollapsed; this.bubble.addEventListener("mouseenter", () => { this.bubble.classList.add("bubble-contact-text"); this.bubble.textContent = this.textExpanded; }); this.bubble.addEventListener("mouseleave", () => { this.bubble.classList.remove("bubble-contact-text"); this.bubble.textContent = this.textCollapsed; }); this.bubble.addEventListener("click", () => { this.toggleForm(); }); this.container.appendChild(this.bubble); parent.appendChild(this.container); } toggleForm() { if (this.showForm) { this.form.remove(); this.showForm = false; } else { this.showForm = true; this.createForm(); } } createForm() { this.form = document.createElement("form"); this.form.className = "contact-form"; this.form.innerHTML = ` <div class="close-btn">x</div> <div class="contact-form-text"> Have feedback or just want to connect?<br/> Send me a quick message — I will get back to you soon! </div> <input type="text" name="user_name" placeholder="Your name" required /> <input type="email" name="user_email" placeholder="Your email" required /> <textarea name="message" placeholder="Your message" required></textarea> <button type="submit">Send</button> `; this.form.querySelector(".close-btn").onclick = () => this.toggleForm(); this.form.onsubmit = (e) => { e.preventDefault(); this.toggleForm(); this.onSubmit(); }; this.container.appendChild(this.form); } } // if (typeof window !== "undefined") { // window.ContactBubble = ContactBubble; // }