Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const require_trigger_css = require("./trigger.css-CuTndetp.cjs"); //#region src/shadow-dom.ts let shadowRoot = null; let hostEl = null; function mountWidget(config) { if (shadowRoot && hostEl) { const mount = shadowRoot.querySelector(".rqd-root"); return { shadow: shadowRoot, host: hostEl, mount }; } hostEl = document.createElement("div"); hostEl.id = "reqdesk-widget"; hostEl.style.position = "fixed"; hostEl.style.zIndex = String(config.zIndex ?? 9999); hostEl.style.inset = "0"; hostEl.style.pointerEvents = "none"; document.body.appendChild(hostEl); shadowRoot = hostEl.attachShadow({ mode: "open" }); const style = document.createElement("style"); style.textContent = require_trigger_css.getWidgetStyles(); shadowRoot.appendChild(style); const mount = document.createElement("div"); mount.className = "rqd-root"; shadowRoot.appendChild(mount); return { shadow: shadowRoot, host: hostEl, mount }; } function unmountWidget() { if (hostEl) { hostEl.remove(); hostEl = null; shadowRoot = null; } } function getShadowRoot() { return shadowRoot; } //#endregion //#region src/ui/fab.ts function createSvg(path) { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("viewBox", "0 0 24 24"); const p = document.createElementNS("http://www.w3.org/2000/svg", "path"); p.setAttribute("d", path); svg.appendChild(p); return svg; } function createFab(position, onClick, label, fabIcon) { const btn = document.createElement("button"); btn.className = `rqd-fab rqd-${position} rqd-fab-labeled rqd-fab-side-${require_trigger_css.positionSide(position)}`; btn.appendChild(createSvg(require_trigger_css.resolveFabIconPath(fabIcon))); const accessibleLabel = label ?? "Open support widget"; if (label) { const span = document.createElement("span"); span.className = "rqd-fab-label"; span.setAttribute("aria-hidden", "true"); span.textContent = label; btn.appendChild(span); } btn.setAttribute("aria-label", accessibleLabel); btn.addEventListener("click", onClick); return btn; } function setFabOpen(fab, isOpen, label, fabIcon) { while (fab.firstChild) fab.removeChild(fab.firstChild); fab.appendChild(createSvg(isOpen ? require_trigger_css.FAB_CLOSE_PATH : require_trigger_css.resolveFabIconPath(fabIcon))); if (isOpen) { fab.classList.remove("rqd-fab-labeled", "rqd-fab-side-start", "rqd-fab-side-end"); fab.setAttribute("aria-label", "Close support widget"); } else { fab.classList.add("rqd-fab-labeled"); if (label) { const span = document.createElement("span"); span.className = "rqd-fab-label"; span.setAttribute("aria-hidden", "true"); span.textContent = label; fab.appendChild(span); } fab.setAttribute("aria-label", label ?? "Open support widget"); } } //#endregion //#region src/ui/ticket-form.ts function createTicketForm(projectId, t, onSuccess, onError) { const form = document.createElement("form"); form.className = "rqd-form"; form.setAttribute("novalidate", ""); const fields = {}; const errors = {}; function addField(name, type, label, opts) { const group = document.createElement("div"); group.className = "rqd-form-group"; const lbl = document.createElement("label"); lbl.className = "rqd-label"; lbl.textContent = label; group.appendChild(lbl); let el; if (type === "textarea") { el = document.createElement("textarea"); el.className = "rqd-textarea"; } else if (type === "select") { el = document.createElement("select"); el.className = "rqd-select"; if (opts?.options) for (const opt of opts.options) { const option = document.createElement("option"); option.value = opt.value; option.textContent = opt.label; el.appendChild(option); } } else { el = document.createElement("input"); el.className = "rqd-input"; el.type = name === "email" ? "email" : "text"; } if (opts?.placeholder && "placeholder" in el) el.placeholder = opts.placeholder; if (opts?.required) el.required = true; el.name = name; group.appendChild(el); const err = document.createElement("div"); err.className = "rqd-error-text"; err.style.display = "none"; group.appendChild(err); fields[name] = el; errors[name] = err; form.appendChild(group); } let hasContent = false; function onBeforeUnload(e) { if (hasContent) e.preventDefault(); } window.addEventListener("beforeunload", onBeforeUnload); form.addEventListener("input", () => { hasContent = Object.values(fields).some((f) => f.value.trim().length > 0); }); addField("title", "input", t("form.title"), { placeholder: t("form.titlePlaceholder"), required: true }); addField("description", "textarea", t("form.description"), { placeholder: t("form.descriptionPlaceholder") }); addField("email", "input", t("form.email"), { placeholder: t("form.emailPlaceholder"), required: true }); addField("priority", "select", t("form.priority"), { options: [ { value: "medium", label: t("form.priorityMedium") }, { value: "low", label: t("form.priorityLow") }, { value: "high", label: t("form.priorityHigh") }, { value: "critical", label: t("form.priorityCritical") } ] }); const submitBtn = document.createElement("button"); submitBtn.type = "submit"; submitBtn.className = "rqd-btn rqd-btn-primary"; submitBtn.textContent = t("form.submit"); form.appendChild(submitBtn); function validate() { let valid = true; const title = fields.title.value.trim(); const email = fields.email.value.trim(); for (const err of Object.values(errors)) { err.style.display = "none"; err.textContent = ""; } if (!title) { errors.title.textContent = t("error.required"); errors.title.style.display = "block"; valid = false; } else if (title.length < 5) { errors.title.textContent = t("error.titleMin"); errors.title.style.display = "block"; valid = false; } if (!email) { errors.email.textContent = t("error.required"); errors.email.style.display = "block"; valid = false; } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { errors.email.textContent = t("error.emailInvalid"); errors.email.style.display = "block"; valid = false; } return valid; } form.addEventListener("submit", async (e) => { e.preventDefault(); if (!validate()) return; submitBtn.disabled = true; submitBtn.textContent = t("form.submitting"); const data = { title: fields.title.value.trim(), description: fields.description.value.trim() || void 0, email: fields.email.value.trim(), priority: fields.priority.value }; try { const result = await require_trigger_css.submitTicket(projectId, data); if (result.trackingToken) require_trigger_css.saveTrackingToken(projectId, result.trackingToken); hasContent = false; window.removeEventListener("beforeunload", onBeforeUnload); onSuccess(result); } catch (err) { onError(err); submitBtn.disabled = false; submitBtn.textContent = t("form.submit"); } }); return form; } function createSuccessView(result, t, onClose, onTrack) { const div = document.createElement("div"); div.className = "rqd-success"; const icon = document.createElement("div"); icon.className = "rqd-success-icon"; icon.textContent = "✅"; div.appendChild(icon); const heading = document.createElement("h3"); heading.textContent = t("success.title"); div.appendChild(heading); const num = document.createElement("p"); num.textContent = t("success.ticketNumber") + result.ticketNumber; div.appendChild(num); if (result.trackingToken) { const hint = document.createElement("p"); hint.textContent = t("success.trackingHint"); hint.style.fontSize = "13px"; hint.style.color = "var(--rqd-text-secondary)"; div.appendChild(hint); const tokenBox = document.createElement("div"); tokenBox.className = "rqd-token-box"; tokenBox.textContent = result.trackingToken; div.appendChild(tokenBox); const copyBtn = document.createElement("button"); copyBtn.className = "rqd-btn rqd-btn-secondary"; copyBtn.textContent = t("success.copyToken"); copyBtn.style.marginBottom = "8px"; copyBtn.addEventListener("click", () => { navigator.clipboard.writeText(result.trackingToken).then(() => { copyBtn.textContent = t("success.copied"); setTimeout(() => { copyBtn.textContent = t("success.copyToken"); }, 2e3); }); }); div.appendChild(copyBtn); if (onTrack) { const trackBtn = document.createElement("button"); trackBtn.className = "rqd-btn rqd-btn-primary"; trackBtn.textContent = t("success.trackNow"); trackBtn.style.marginTop = "4px"; trackBtn.addEventListener("click", onTrack); div.appendChild(trackBtn); } } const closeBtn = document.createElement("button"); closeBtn.className = "rqd-btn rqd-btn-secondary"; closeBtn.textContent = t("success.close"); closeBtn.style.marginTop = "8px"; closeBtn.addEventListener("click", onClose); div.appendChild(closeBtn); return div; } //#endregion //#region src/ui/tracker.ts function createTrackerView(t, onTracked, onReplySent, onError, onBack, prefillToken) { const container = document.createElement("div"); container.className = "rqd-tracker"; if (prefillToken) { renderLoading(container, t); doTrack(prefillToken, container, t, onTracked, onReplySent, onError, onBack); } else renderTokenInput(container, t, onTracked, onReplySent, onError, onBack); return container; } function renderTokenInput(container, t, onTracked, onReplySent, onError, onBack) { while (container.firstChild) container.removeChild(container.firstChild); const group = document.createElement("div"); group.className = "rqd-form-group"; const label = document.createElement("label"); label.className = "rqd-label"; label.textContent = t("tracker.title"); group.appendChild(label); const input = document.createElement("input"); input.className = "rqd-input"; input.placeholder = t("tracker.tokenPlaceholder"); input.type = "text"; group.appendChild(input); const err = document.createElement("div"); err.className = "rqd-error-text"; err.style.display = "none"; group.appendChild(err); container.appendChild(group); const btn = document.createElement("button"); btn.className = "rqd-btn rqd-btn-primary"; btn.textContent = t("tracker.submit"); btn.addEventListener("click", () => { const token = input.value.trim(); if (!token) { err.textContent = t("error.required"); err.style.display = "block"; return; } err.style.display = "none"; btn.disabled = true; btn.textContent = t("tracker.tracking"); doTrack(token, container, t, onTracked, onReplySent, onError, onBack); }); container.appendChild(btn); } function renderLoading(container, t) { while (container.firstChild) container.removeChild(container.firstChild); const p = document.createElement("p"); p.textContent = t("tracker.tracking"); p.style.textAlign = "center"; p.style.color = "var(--rqd-text-secondary)"; container.appendChild(p); } async function doTrack(token, container, t, onTracked, onReplySent, onError, onBack) { try { const result = await require_trigger_css.trackTicket(token); onTracked(result); renderTicketDetail(container, token, result, t, onReplySent, onError, onBack); } catch (err) { onError(err); renderTokenInput(container, t, onTracked, onReplySent, onError, onBack); } } function renderTicketDetail(container, token, ticket, t, onReplySent, onError, onBack) { while (container.firstChild) container.removeChild(container.firstChild); if (onBack) { const backBtn = document.createElement("button"); backBtn.className = "rqd-btn rqd-btn-secondary"; backBtn.textContent = t("tracker.back"); backBtn.style.marginBottom = "12px"; backBtn.addEventListener("click", onBack); container.appendChild(backBtn); } const info = document.createElement("div"); info.className = "rqd-ticket-info"; const titleRow = document.createElement("div"); titleRow.style.fontWeight = "600"; titleRow.style.marginBottom = "8px"; titleRow.textContent = `${ticket.ticketNumber} — ${ticket.title}`; info.appendChild(titleRow); for (const [label, value] of [ [t("tracker.status"), ticket.status], [t("tracker.priority"), ticket.priority], [t("tracker.created"), new Date(ticket.createdAt).toLocaleDateString()] ]) { const row = document.createElement("div"); row.className = "rqd-ticket-row"; const lbl = document.createElement("span"); lbl.className = "rqd-ticket-label"; lbl.textContent = label; row.appendChild(lbl); const badge = document.createElement("span"); badge.className = "rqd-badge"; badge.textContent = value; row.appendChild(badge); info.appendChild(row); } container.appendChild(info); const repliesLabel = document.createElement("div"); repliesLabel.className = "rqd-label"; repliesLabel.textContent = t("tracker.replies"); repliesLabel.style.marginBottom = "8px"; container.appendChild(repliesLabel); if (ticket.replies.length === 0) { const noReplies = document.createElement("p"); noReplies.textContent = t("tracker.noReplies"); noReplies.style.color = "var(--rqd-text-secondary)"; noReplies.style.fontSize = "13px"; container.appendChild(noReplies); } else for (const reply of ticket.replies) { const replyEl = document.createElement("div"); replyEl.className = "rqd-reply"; const header = document.createElement("div"); header.className = "rqd-reply-header"; const authorSpan = document.createElement("span"); authorSpan.textContent = reply.authorName; if (reply.isStaff) authorSpan.className = "rqd-reply-staff"; header.appendChild(authorSpan); const dateSpan = document.createElement("span"); dateSpan.textContent = new Date(reply.createdAt).toLocaleString(); header.appendChild(dateSpan); replyEl.appendChild(header); const body = document.createElement("div"); body.className = "rqd-reply-body"; body.textContent = reply.body; replyEl.appendChild(body); container.appendChild(replyEl); } const replyGroup = document.createElement("div"); replyGroup.className = "rqd-form-group"; replyGroup.style.marginTop = "12px"; const textarea = document.createElement("textarea"); textarea.className = "rqd-textarea"; textarea.placeholder = t("tracker.replyPlaceholder"); textarea.rows = 3; replyGroup.appendChild(textarea); container.appendChild(replyGroup); const sendBtn = document.createElement("button"); sendBtn.className = "rqd-btn rqd-btn-primary"; sendBtn.textContent = t("tracker.sendReply"); sendBtn.addEventListener("click", async () => { const body = textarea.value.trim(); if (!body) return; sendBtn.disabled = true; sendBtn.textContent = t("tracker.sending"); try { await require_trigger_css.submitTrackingReply(token, body); onReplySent({ token, body }); renderTicketDetail(container, token, await require_trigger_css.trackTicket(token), t, onReplySent, onError, onBack); } catch (err) { onError(err); sendBtn.disabled = false; sendBtn.textContent = t("tracker.sendReply"); } }); container.appendChild(sendBtn); } //#endregion //#region src/ui/portal.ts function createPortalView(t, fetchTickets, fetchTicketDetail, submitReply, projectId, onTicketCreated, onError, pollingInterval) { const container = document.createElement("div"); container.className = "rqd-portal"; let currentView = "list"; let pollTimer; function renderList() { currentView = "list"; while (container.firstChild) container.removeChild(container.firstChild); const header = document.createElement("div"); header.style.display = "flex"; header.style.justifyContent = "space-between"; header.style.alignItems = "center"; header.style.marginBottom = "12px"; const title = document.createElement("span"); title.style.fontWeight = "600"; title.textContent = t("portal.myTickets"); header.appendChild(title); const newBtn = document.createElement("button"); newBtn.className = "rqd-btn rqd-btn-primary"; newBtn.style.width = "auto"; newBtn.style.padding = "6px 14px"; newBtn.style.fontSize = "13px"; newBtn.textContent = t("portal.newTicket"); newBtn.addEventListener("click", renderNewTicketForm); header.appendChild(newBtn); container.appendChild(header); const loading = document.createElement("p"); loading.textContent = "..."; loading.style.textAlign = "center"; loading.style.color = "var(--rqd-text-secondary)"; container.appendChild(loading); fetchTickets().then((tickets) => { loading.remove(); if (tickets.length === 0) { const empty = document.createElement("p"); empty.textContent = t("portal.noTickets"); empty.style.textAlign = "center"; empty.style.color = "var(--rqd-text-secondary)"; empty.style.padding = "24px 0"; container.appendChild(empty); return; } for (const ticket of tickets) { const row = document.createElement("div"); row.className = "rqd-ticket-info"; row.style.cursor = "pointer"; row.style.marginBottom = "8px"; const top = document.createElement("div"); top.style.display = "flex"; top.style.justifyContent = "space-between"; top.style.marginBottom = "4px"; const num = document.createElement("span"); num.style.fontWeight = "600"; num.style.fontSize = "13px"; num.textContent = ticket.ticketNumber; top.appendChild(num); const badge = document.createElement("span"); badge.className = "rqd-badge"; badge.textContent = ticket.status; top.appendChild(badge); row.appendChild(top); const titleEl = document.createElement("div"); titleEl.style.fontSize = "14px"; titleEl.textContent = ticket.title; row.appendChild(titleEl); const date = document.createElement("div"); date.style.fontSize = "12px"; date.style.color = "var(--rqd-text-secondary)"; date.style.marginTop = "4px"; date.textContent = new Date(ticket.createdAt).toLocaleDateString(); row.appendChild(date); row.addEventListener("click", () => renderDetail(ticket.id)); container.appendChild(row); } }).catch((err) => { loading.remove(); onError(err); }); if (pollingInterval && pollingInterval > 0) { stopPolling(); pollTimer = setInterval(() => { if (currentView === "list") renderList(); }, pollingInterval); } } function renderDetail(ticketId) { currentView = "detail"; stopPolling(); while (container.firstChild) container.removeChild(container.firstChild); const backBtn = document.createElement("button"); backBtn.className = "rqd-btn rqd-btn-secondary"; backBtn.textContent = t("tracker.back"); backBtn.style.marginBottom = "12px"; backBtn.addEventListener("click", renderList); container.appendChild(backBtn); const loading = document.createElement("p"); loading.textContent = "..."; loading.style.textAlign = "center"; container.appendChild(loading); fetchTicketDetail(ticketId).then((ticket) => { loading.remove(); const info = document.createElement("div"); info.className = "rqd-ticket-info"; const titleRow = document.createElement("div"); titleRow.style.fontWeight = "600"; titleRow.style.marginBottom = "8px"; titleRow.textContent = `${ticket.ticketNumber} — ${ticket.title}`; info.appendChild(titleRow); for (const [label, value] of [[t("tracker.status"), ticket.status], [t("tracker.priority"), ticket.priority]]) { const row = document.createElement("div"); row.className = "rqd-ticket-row"; const lbl = document.createElement("span"); lbl.className = "rqd-ticket-label"; lbl.textContent = label; row.appendChild(lbl); const badge = document.createElement("span"); badge.className = "rqd-badge"; badge.textContent = value; row.appendChild(badge); info.appendChild(row); } container.appendChild(info); const repliesLabel = document.createElement("div"); repliesLabel.className = "rqd-label"; repliesLabel.textContent = t("tracker.replies"); repliesLabel.style.marginBottom = "8px"; container.appendChild(repliesLabel); if (ticket.replies.length === 0) { const noReplies = document.createElement("p"); noReplies.textContent = t("tracker.noReplies"); noReplies.style.color = "var(--rqd-text-secondary)"; noReplies.style.fontSize = "13px"; container.appendChild(noReplies); } else for (const reply of ticket.replies) { const replyEl = document.createElement("div"); replyEl.className = "rqd-reply"; const header = document.createElement("div"); header.className = "rqd-reply-header"; const authorSpan = document.createElement("span"); authorSpan.textContent = reply.authorName; if (reply.isStaff) authorSpan.className = "rqd-reply-staff"; header.appendChild(authorSpan); const dateSpan = document.createElement("span"); dateSpan.textContent = new Date(reply.createdAt).toLocaleString(); header.appendChild(dateSpan); replyEl.appendChild(header); const body = document.createElement("div"); body.className = "rqd-reply-body"; body.textContent = reply.body; replyEl.appendChild(body); container.appendChild(replyEl); } const replyGroup = document.createElement("div"); replyGroup.className = "rqd-form-group"; replyGroup.style.marginTop = "12px"; const textarea = document.createElement("textarea"); textarea.className = "rqd-textarea"; textarea.placeholder = t("tracker.replyPlaceholder"); textarea.rows = 3; replyGroup.appendChild(textarea); container.appendChild(replyGroup); const sendBtn = document.createElement("button"); sendBtn.className = "rqd-btn rqd-btn-primary"; sendBtn.textContent = t("tracker.sendReply"); sendBtn.addEventListener("click", async () => { const body = textarea.value.trim(); if (!body) return; sendBtn.disabled = true; sendBtn.textContent = t("tracker.sending"); try { await submitReply(ticketId, body); renderDetail(ticketId); } catch (err) { onError(err); sendBtn.disabled = false; sendBtn.textContent = t("tracker.sendReply"); } }); container.appendChild(sendBtn); }).catch((err) => { loading.remove(); onError(err); }); } function renderNewTicketForm() { currentView = "new"; stopPolling(); while (container.firstChild) container.removeChild(container.firstChild); const backBtn = document.createElement("button"); backBtn.className = "rqd-btn rqd-btn-secondary"; backBtn.textContent = t("tracker.back"); backBtn.style.marginBottom = "12px"; backBtn.addEventListener("click", renderList); container.appendChild(backBtn); const fields = {}; function addField(name, type, label, placeholder) { const group = document.createElement("div"); group.className = "rqd-form-group"; const lbl = document.createElement("label"); lbl.className = "rqd-label"; lbl.textContent = label; group.appendChild(lbl); const el = type === "textarea" ? document.createElement("textarea") : document.createElement("input"); el.className = type === "textarea" ? "rqd-textarea" : "rqd-input"; el.placeholder = placeholder; el.name = name; group.appendChild(el); fields[name] = el; container.appendChild(group); } addField("title", "input", t("form.title"), t("form.titlePlaceholder")); addField("description", "textarea", t("form.description"), t("form.descriptionPlaceholder")); const submitBtn = document.createElement("button"); submitBtn.className = "rqd-btn rqd-btn-primary"; submitBtn.textContent = t("form.submit"); submitBtn.addEventListener("click", async () => { const title = fields.title.value.trim(); if (!title || title.length < 5) return; submitBtn.disabled = true; submitBtn.textContent = t("form.submitting"); const data = { title, description: fields.description.value.trim() || void 0, email: "", priority: "medium" }; try { onTicketCreated(await require_trigger_css.submitTicket(projectId, data)); renderList(); } catch (err) { onError(err); submitBtn.disabled = false; submitBtn.textContent = t("form.submit"); } }); container.appendChild(submitBtn); } function stopPolling() { if (pollTimer) { clearInterval(pollTimer); pollTimer = void 0; } } renderList(); return container; } //#endregion //#region src/ui/trigger.ts const CHAT_PATH = "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"; function buildDefaultIcon() { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("viewBox", "0 0 24 24"); svg.setAttribute("aria-hidden", "true"); const p = document.createElementNS("http://www.w3.org/2000/svg", "path"); p.setAttribute("d", CHAT_PATH); svg.appendChild(p); return svg; } function parseTrustedMarkup(markup) { const frag = document.createDocumentFragment(); const trimmed = markup.trim(); if (!trimmed) return frag; if (trimmed.startsWith("${trimmed}`, "text/html").body; while (body.firstChild) frag.appendChild(document.importNode(body.firstChild, true)); } catch { frag.appendChild(document.createTextNode(markup)); } return frag; } function resolveTarget(target) { if (!target || target === "menu") return { kind: "menu" }; return { kind: "action", id: target.actionId }; } function applyDisplayOverride(display) { if (!display) return; const registry = require_trigger_css.getRegistry(); if (typeof display === "string") registry.setDisplayMode(display); else if (display.mode) registry.setDisplayMode(display.mode, display.side); } function mountTrigger(target, opts = {}) { if (typeof document === "undefined") return { unmount() {} }; require_trigger_css.injectTriggerStyles(); const element = typeof target === "string" ? document.querySelector(target) : target; if (!element) throw new Error(`[reqdesk] mountTrigger: target not found (${String(target)})`); const variant = opts.variant ?? "pill"; const btn = document.createElement("button"); btn.type = "button"; btn.className = `rqd-trigger rqd-trigger--${variant}${opts.className ? ` ${opts.className}` : ""}`; if (opts.style) { for (const [k, v] of Object.entries(opts.style)) if (v != null) btn.style[k] = String(v); } if (opts.icon !== null) if (typeof opts.icon === "string") btn.appendChild(parseTrustedMarkup(opts.icon)); else if (opts.icon instanceof HTMLElement) btn.appendChild(opts.icon); else btn.appendChild(buildDefaultIcon()); const label = opts.label ?? "Open support"; const labelSpan = document.createElement("span"); labelSpan.className = "rqd-trigger-label"; labelSpan.textContent = label; btn.appendChild(labelSpan); btn.setAttribute("aria-label", label); btn.setAttribute("aria-haspopup", "menu"); btn.setAttribute("aria-expanded", "false"); const registry = require_trigger_css.getRegistry(); const targetResolved = resolveTarget(opts.target); const handleClick = (e) => { registry.recordActivator(btn); applyDisplayOverride(opts.display); if (targetResolved.kind === "menu") registry.openMenu(); else registry.openAction(targetResolved.id); e.stopPropagation(); }; btn.addEventListener("click", handleClick); const unsubscribe = registry.subscribe((snap) => { btn.setAttribute("aria-expanded", String(snap.isOpen)); }); element.appendChild(btn); return { unmount() { unsubscribe(); btn.removeEventListener("click", handleClick); if (btn.parentElement) btn.parentElement.removeChild(btn); } }; } //#endregion //#region src/index.ts const translations = { en: require_trigger_css.en, ar: require_trigger_css.ar }; let config = null; let isOpen = false; let currentLang = "en"; let fab = null; let panel = null; let mount = null; let currentTab = "form"; let pendingTrackToken; let registry = null; function t(key) { const overrides = config?.translations; if (overrides?.[key]) return overrides[key]; return (translations[currentLang] ?? translations.en)[key] ?? key; } function emit(event, data) { registry?.emitEvent(event, data); } function deriveApiUrl() { return window.location.origin; } function extractProjectId() { return "_current"; } function renderPanel() { if (!mount || !config) return; if (panel && panel.parentNode === mount) { mount.removeChild(panel); panel = null; } const position = require_trigger_css.normalizePosition(config.position); if (!config.inline) { panel = document.createElement("div"); panel.className = `rqd-panel rqd-${position}`; panel.style.cssText = require_trigger_css.themeToVars(config.theme); const header = document.createElement("div"); header.className = "rqd-header"; const title = document.createElement("span"); title.className = "rqd-header-title"; title.textContent = t("widget.title"); header.appendChild(title); const closeBtn = document.createElement("button"); closeBtn.className = "rqd-header-close"; closeBtn.textContent = "✕"; closeBtn.addEventListener("click", close); header.appendChild(closeBtn); panel.appendChild(header); const body = document.createElement("div"); body.className = "rqd-body"; if (config.widget === "support-portal" && config.customer?.email) renderPortal(body); else { const tabs = document.createElement("div"); tabs.className = "rqd-tabs"; const formTab = document.createElement("button"); formTab.className = `rqd-tab${currentTab === "form" ? " rqd-active" : ""}`; formTab.textContent = t("widget.newTicket"); formTab.addEventListener("click", () => switchTab("form", body, tabs)); const trackerTab = document.createElement("button"); trackerTab.className = `rqd-tab${currentTab === "tracker" ? " rqd-active" : ""}`; trackerTab.textContent = t("widget.trackTicket"); trackerTab.addEventListener("click", () => switchTab("tracker", body, tabs)); tabs.appendChild(formTab); tabs.appendChild(trackerTab); panel.appendChild(tabs); if (currentTab === "form") renderForm(body); else renderTracker(body); } panel.appendChild(body); mount.appendChild(panel); } else { const container = typeof config.container === "string" ? document.querySelector(config.container) : config.container; if (container) { const inline = document.createElement("div"); inline.className = "rqd-inline"; inline.style.cssText = require_trigger_css.themeToVars(config.theme); const body = document.createElement("div"); body.className = "rqd-body"; renderForm(body); inline.appendChild(body); container.appendChild(inline); return; } } } function renderPortal(container) { if (!config) return; const portalView = createPortalView(t, async () => [], async (id) => ({ id, ticketNumber: "", title: "", status: "", priority: "", createdAt: "", replies: [] }), async (_ticketId, _body) => {}, extractProjectId(), (data) => emit("ticket:created", data), (err) => emit("error", err), 3e4); container.appendChild(portalView); } function switchTab(tab, body, tabs) { currentTab = tab; pendingTrackToken = void 0; tabs.querySelectorAll(".rqd-tab").forEach((btn, i) => { btn.classList.toggle("rqd-active", i === 0 && tab === "form" || i === 1 && tab === "tracker"); }); while (body.firstChild) body.removeChild(body.firstChild); if (tab === "form") renderForm(body); else renderTracker(body); } function renderForm(container) { if (!config) return; const form = createTicketForm(extractProjectId(), t, (result) => { emit("ticket:created", result); renderSuccess(container, result); }, (err) => { emit("error", err); }); container.appendChild(form); } function renderTracker(container) { const view = createTrackerView(t, (data) => emit("ticket:tracked", data), (data) => emit("reply:sent", data), (err) => emit("error", err), void 0, pendingTrackToken); container.appendChild(view); } function renderSuccess(container, result) { while (container.firstChild) container.removeChild(container.firstChild); const view = createSuccessView(result, t, () => close(), result.trackingToken ? () => { pendingTrackToken = result.trackingToken; if (panel) { const body = panel.querySelector(".rqd-body"); const tabs = panel.querySelector(".rqd-tabs"); if (body && tabs) switchTab("tracker", body, tabs); } } : void 0); container.appendChild(view); } function init(cfg) { if (config) return; const saved = require_trigger_css.loadWidgetConfig(cfg.apiKey); const resolvedPosition = require_trigger_css.normalizePosition(cfg.position ?? saved?.position); config = { ...cfg, position: resolvedPosition, language: cfg.language ?? saved?.language ?? "en", widget: cfg.widget ?? saved?.widget ?? "ticket-form", theme: { ...saved?.theme, ...cfg.theme } }; currentLang = config.language ?? "en"; require_trigger_css.saveWidgetConfig(cfg.apiKey, { position: resolvedPosition, language: config.language, widget: config.widget, theme: config.theme }); registry = require_trigger_css.getRegistry(); registry.setApiKeyForStorage(cfg.apiKey); registry.setInitialPreferences(cfg.initialPreferences ?? {}); registry.setConfigDisplay(cfg.display); registry.setMenuCloseOnAction(cfg.menuCloseOnAction ?? true); registry.setHostPreferencesCallback(cfg.onPreferencesChange); registry.setContext({ user: cfg.customer ? { email: cfg.customer.email, name: cfg.customer.name } : null, locale: currentLang }); const resolvedPrefs = require_trigger_css.resolvePreferences({ apiKey: cfg.apiKey, initialPreferences: cfg.initialPreferences, userPreferences: cfg.userPreferences }); registry.initPreferencesSnapshot(resolvedPrefs); if (cfg.actions && cfg.actions.length > 0) for (const action of cfg.actions) registry.addAction(action); require_trigger_css.configureWidgetClient(deriveApiUrl(), cfg.apiKey); require_trigger_css.setWidgetCustomer(cfg.customer ?? null); if (cfg.inline) { renderPanel(); return; } const { mount: m } = mountWidget({ zIndex: cfg.theme?.zIndex }); mount = m; const shadow = getShadowRoot(); if (shadow) { const root = shadow.querySelector(".rqd-root"); if (root) root.style.cssText = require_trigger_css.themeToVars(cfg.theme); } const host = document.getElementById("reqdesk-widget"); if (host && currentLang === "ar") host.setAttribute("dir", "rtl"); if (require_trigger_css.getTrackingTokens(cfg.apiKey).length > 0) currentTab = "tracker"; if (!cfg.hideFab) { fab = createFab(resolvedPosition, toggle, cfg.theme?.brandName ?? t("widget.title"), cfg.fabIcon); mount.appendChild(fab); } } function open() { if (!config || isOpen) return; isOpen = true; if (fab) setFabOpen(fab, true, void 0, config.fabIcon); renderPanel(); registry?.open(); } function close() { if (!isOpen) return; isOpen = false; const fabLabel = config?.theme?.brandName ?? t("widget.title"); if (fab) setFabOpen(fab, false, fabLabel, config?.fabIcon); if (panel) { panel.remove(); panel = null; } registry?.close(); } function toggle() { if (isOpen) close(); else open(); } function openMenu() { registry?.openMenu(); if (!isOpen) open(); } function openAction(id, input) { registry?.openAction(id, input); if (!isOpen) open(); } function setDisplayMode(mode, side) { registry?.setDisplayMode(mode, side); } function setPreferences(next) { registry?.setPreferences(next); } function getPreferences() { return registry?.getPreferences() ?? {}; } function addAction(action) { if (!registry) return () => {}; return registry.addAction(action); } function removeAction(id) { registry?.removeAction(id); } function setLanguage(lang) { currentLang = lang; if (config) { config.language = lang; require_trigger_css.saveWidgetConfig(config.apiKey, { language: lang }); } registry?.setContext({ locale: lang }); const host = document.getElementById("reqdesk-widget"); if (host) host.setAttribute("dir", lang === "ar" ? "rtl" : "ltr"); if (isOpen && panel && mount) { panel.remove(); panel = null; renderPanel(); } } function setTheme(theme) { if (!config) return; config.theme = { ...config.theme, ...theme }; require_trigger_css.saveWidgetConfig(config.apiKey, { theme: config.theme }); if (panel) panel.style.cssText = require_trigger_css.themeToVars(config.theme); } function on(event, callback) { if (!registry) return () => {}; return registry.on(event, callback); } function identify(customer) { if (!config) return; config.customer = customer; require_trigger_css.setWidgetCustomer(customer); registry?.setContext({ user: { email: customer.email, name: customer.name } }); if (isOpen && panel && mount) { panel.remove(); panel = null; renderPanel(); } } function destroy() { close(); unmountWidget(); registry?.destroy(); registry = null; config = null; fab = null; panel = null; mount = null; isOpen = false; } //#endregion exports.addAction = addAction; exports.close = close; exports.destroy = destroy; exports.getPreferences = getPreferences; exports.identify = identify; exports.init = init; exports.mountTrigger = mountTrigger; exports.on = on; exports.open = open; exports.openAction = openAction; exports.openMenu = openMenu; exports.removeAction = removeAction; exports.setDisplayMode = setDisplayMode; exports.setLanguage = setLanguage; exports.setPreferences = setPreferences; exports.setTheme = setTheme; exports.toggle = toggle;