(function () {
"use strict";
const style = document.createElement("style");
style.setAttribute("data-paperq-auth-styles", "");
style.textContent = `.auth-dialog {
--paperq-auth-text: #000000;
--paperq-auth-muted: #8a8c93;
--paperq-auth-panel: #ffffff;
--paperq-auth-line: rgba(206, 206, 214, 0.5);
--paperq-auth-primary: #cdfa85;
--paperq-auth-secondary: #f1f2f4;
--paperq-auth-danger: #f75555;
--paperq-auth-shadow: 0 0 13.9px 1px rgba(21, 21, 20, 0.2);
--paperq-auth-input-shadow: 0 0 6.5px 1px rgba(21, 21, 20, 0.08);
--paperq-auth-radius-window: 20px;
--paperq-auth-radius-input: 12px;
--paperq-auth-radius-button: 8px;
--paperq-auth-font: "Golos Text", Inter, Arial, sans-serif;
width: 300px;
max-width: calc(100vw - 24px);
border: 0;
padding: 0;
background: transparent;
color: var(--paperq-auth-text);
font-family: var(--paperq-auth-font);
overflow: visible;
}
.auth-dialog,
.auth-dialog *,
.auth-dialog *::before,
.auth-dialog *::after {
box-sizing: border-box;
}
.auth-dialog button,
.auth-dialog input {
appearance: none;
min-width: 0;
margin: 0;
font: inherit;
letter-spacing: 0;
}
.auth-dialog button {
cursor: pointer;
}
.auth-dialog::backdrop {
background: rgba(0, 0, 0, 0.42);
}
.auth-dialog__panel {
position: relative;
display: flex;
width: 100%;
flex-direction: column;
align-items: stretch;
gap: 10px;
border: 0;
border-radius: var(--paperq-auth-radius-window);
background: var(--paperq-auth-panel);
box-shadow: var(--paperq-auth-shadow);
padding: 24px 16px 16px;
}
.auth-dialog--forced .auth-dialog__close,
.auth-dialog--forced [data-auth-later] {
display: none;
}
.auth-step {
display: flex;
width: 100%;
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.auth-step[hidden] {
display: none;
}
.auth-dialog h2 {
width: 100%;
margin: 0;
padding: 0 22px;
color: var(--paperq-auth-text);
font-size: 24px;
font-weight: 600;
line-height: 1;
text-align: center;
}
.auth-dialog p {
width: 100%;
margin: 0;
color: var(--paperq-auth-text);
font-size: 12px;
font-weight: 500;
line-height: 1.3;
text-align: center;
}
.auth-dialog label {
display: flex;
width: 100%;
flex-direction: column;
gap: 0;
margin: 0;
color: transparent;
font-size: 0;
line-height: 0;
}
.auth-step input {
display: flex;
width: 100%;
height: 45px;
align-items: center;
border: 1px solid var(--paperq-auth-line);
border-radius: var(--paperq-auth-radius-input);
background: var(--paperq-auth-panel);
box-shadow: var(--paperq-auth-input-shadow);
color: var(--paperq-auth-text);
font-size: 12px;
font-weight: 400;
line-height: 1.5;
outline: 0;
padding: 8px 8px 8px 16px;
}
.auth-step input::placeholder {
color: var(--paperq-auth-muted);
opacity: 1;
}
.auth-step input:focus {
border-color: rgba(206, 206, 214, 0.9);
box-shadow:
var(--paperq-auth-input-shadow),
0 0 0 2px rgba(205, 250, 133, 0.22);
}
.auth-step input[aria-invalid="true"],
.auth-step input.is-error {
border-color: var(--paperq-auth-danger);
box-shadow: 0 0 6.5px 1px rgba(247, 85, 85, 0.12);
}
.auth-dialog strong {
font-weight: 500;
}
.otp-demo {
display: none;
}
.form-error {
min-height: 13px;
margin: -4px 0 0;
color: var(--paperq-auth-danger);
font-size: 10px;
font-weight: 400;
line-height: 1.3;
text-align: left;
}
.auth-dialog__actions {
display: flex;
width: 100%;
align-items: center;
gap: 8px;
margin-top: 0;
}
.auth-dialog .primary-button,
.auth-dialog .secondary-button {
display: inline-flex;
height: 40px;
flex: 1 1 0;
align-items: center;
justify-content: center;
border: 0;
border-radius: var(--paperq-auth-radius-button);
color: var(--paperq-auth-text);
font-size: 12px;
font-weight: 500;
line-height: 1;
padding: 10px 12px;
text-align: center;
text-decoration: none;
white-space: nowrap;
transition:
background 140ms ease,
color 140ms ease,
opacity 140ms ease,
transform 140ms ease;
}
.auth-dialog .primary-button {
background: var(--paperq-auth-primary);
}
.auth-dialog .secondary-button {
background: var(--paperq-auth-secondary);
}
.auth-dialog .primary-button:hover,
.auth-dialog .secondary-button:hover {
transform: translateY(-1px);
}
.auth-dialog .primary-button:active,
.auth-dialog .secondary-button:active {
transform: translateY(0);
}
.auth-dialog .icon-button.auth-dialog__close {
position: absolute;
top: 10px;
right: 10px;
display: inline-flex;
width: 24px;
height: 24px;
align-items: center;
justify-content: center;
border: 0;
border-radius: 999px;
background: transparent;
box-shadow: none;
color: #a9abb2;
padding: 0;
}
.auth-dialog .icon-button.auth-dialog__close span {
display: block;
font-size: 24px;
font-weight: 300;
line-height: 1;
transform: translateY(-1px);
}
.auth-dialog .icon-button.auth-dialog__close:hover {
background: rgba(0, 0, 0, 0.04);
color: var(--paperq-auth-muted);
}
.auth-dialog [disabled] {
cursor: default;
opacity: 0.7;
transform: none;
}
@media (max-width: 360px) {
.auth-dialog {
width: calc(100vw - 24px);
}
}`;
document.head.appendChild(style);
class AuthPopup {
constructor(options = {}) {
this.currentEmail = options.initialEmail || "";
this.onOtpRequested = options.onOtpRequested || noop;
this.onAuthenticated = options.onAuthenticated || noop;
this.onClose = options.onClose || noop;
this.forced = false;
this.step = "email";
this.pendingEmail = "";
this.inFlight = false;
this.els = {
dialog: document.querySelector("[data-auth-dialog]"),
form: document.querySelector("[data-auth-form]"),
close: document.querySelector("[data-auth-close]"),
later: document.querySelector("[data-auth-later]"),
title: document.querySelector("[data-auth-title]"),
copy: document.querySelector("[data-auth-copy]"),
emailStep: document.querySelector('[data-auth-step="email"]'),
otpStep: document.querySelector('[data-auth-step="otp"]'),
emailInput: document.querySelector("[data-email-input]"),
otpInput: document.querySelector("[data-otp-input]"),
otpEmail: document.querySelector("[data-otp-email]"),
emailError: document.querySelector("[data-email-error]"),
otpError: document.querySelector("[data-otp-error]"),
changeEmail: document.querySelector("[data-change-email]"),
};
this.bindEvents();
}
bindEvents() {
this.els.form.addEventListener("submit", (event) => {
event.preventDefault();
this.submitCurrentStep();
});
this.els.close.addEventListener("click", () => this.close());
this.els.later.addEventListener("click", () => this.close());
this.els.changeEmail.addEventListener("click", () => this.showEmailStep());
this.els.dialog.addEventListener("cancel", (event) => {
if (this.forced) {
event.preventDefault();
}
});
this.els.otpInput.addEventListener("input", () => {
this.els.otpInput.value = this.els.otpInput.value.replace(/\D/g, "").slice(0, 6);
this.els.otpError.textContent = "";
});
this.els.emailInput.addEventListener("input", () => {
this.els.emailError.textContent = "";
});
}
open(options = {}) {
this.forced = Boolean(options.required);
this.pendingEmail = "";
this.currentEmail = options.email || this.currentEmail || "";
this.showEmailStep();
this.els.dialog.classList.toggle("auth-dialog--forced", this.forced);
this.els.close.hidden = this.forced;
this.els.later.hidden = this.forced;
this.els.title.textContent = options.title || (this.forced ? "Войдите в Paper Q" : "Войти в Paper Q");
this.els.copy.textContent =
options.copy ||
(this.forced
? "После трех вопросов нужен email. Мы отправим одноразовый код, он будет действителен 5 минут."
: "Укажите email. Если аккаунта еще нет, он будет создан после подтверждения одноразового кода.");
if (typeof this.els.dialog.showModal === "function" && !this.els.dialog.open) {
this.els.dialog.showModal();
}
}
close() {
if (this.forced) return false;
this.forceClose();
return true;
}
forceClose() {
this.forced = false;
this.els.dialog.classList.remove("auth-dialog--forced");
this.els.close.hidden = false;
this.els.later.hidden = false;
if (this.els.dialog.open) {
this.els.dialog.close();
}
this.onClose();
}
setEmail(email) {
this.currentEmail = String(email || "").trim();
}
showEmailStep() {
this.step = "email";
this.els.emailStep.hidden = false;
this.els.otpStep.hidden = true;
this.els.emailInput.value = this.pendingEmail || this.currentEmail || "";
this.els.emailError.textContent = "";
this.els.otpError.textContent = "";
window.setTimeout(() => this.els.emailInput.focus(), 30);
}
showOtpStep(email) {
this.step = "otp";
this.pendingEmail = email;
this.els.emailStep.hidden = true;
this.els.otpStep.hidden = false;
this.els.otpEmail.textContent = email;
this.els.otpInput.value = "";
this.els.otpError.textContent = "";
window.setTimeout(() => this.els.otpInput.focus(), 30);
}
async submitCurrentStep() {
if (this.inFlight) return;
this.inFlight = true;
this.setDisabled(true);
try {
if (this.step === "email") {
await this.submitEmailStep();
} else {
await this.submitOtpStep();
}
} finally {
this.inFlight = false;
this.setDisabled(false);
}
}
async submitEmailStep() {
const email = this.els.emailInput.value.trim();
if (!isValidEmail(email)) {
this.els.emailError.textContent = "Введите корректный email.";
return;
}
try {
await this.onOtpRequested({ email });
this.showOtpStep(email);
} catch (error) {
this.els.emailError.textContent = getErrorMessage(error);
}
}
async submitOtpStep() {
const code = this.els.otpInput.value.trim();
if (!/^\d{6}$/.test(code)) {
this.els.otpError.textContent = "Введите 6 цифр из письма.";
return;
}
const email = this.pendingEmail || this.els.emailInput.value.trim();
try {
await this.onAuthenticated({ email, code });
this.currentEmail = email;
this.forceClose();
} catch (error) {
this.els.otpError.textContent = getErrorMessage(error);
}
}
setDisabled(disabled) {
this.els.form.querySelectorAll("button, input").forEach((element) => {
if (element === this.els.close || element === this.els.later) return;
element.disabled = disabled;
});
}
}
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function getErrorMessage(error) {
if (error && error.message) return error.message;
return "Не удалось выполнить запрос. Попробуйте еще раз.";
}
function noop() {}
window.PaperQAuthPopup = {
version: "paperq-auth-popup-v2",
create(options) {
return new AuthPopup(options);
},
};
})();