import { html, LitElement, render as litRender } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { translateText } from "../Utils"; /** * A reusable inline confirmation dialog. * * Usage: * ```html * doThing()} * @cancel=${() => {}} * > * ``` * * For ban-style flows, add a textarea: * ```html * ban(e.detail.text)} * @cancel=${() => {}} * > * ``` */ @customElement("confirm-dialog") export class ConfirmDialog extends LitElement { @property() message = ""; @property() variant: "danger" | "warning" = "danger"; @property() textareaPlaceholder = ""; @property({ type: Boolean }) disabled = false; @state() private text = ""; private portal: HTMLDivElement | null = null; createRenderRoot() { return this; } connectedCallback() { super.connectedCallback(); this.portal = document.createElement("div"); document.body.appendChild(this.portal); } disconnectedCallback() { super.disconnectedCallback(); if (this.portal) { litRender(html``, this.portal); this.portal.remove(); this.portal = null; } } render() { if (this.portal) { litRender(this.renderOverlay(), this.portal); } return html``; } private renderOverlay() { const isDanger = this.variant === "danger"; const borderColor = isDanger ? "border-red-500/50" : "border-amber-500/50"; const cardBg = "bg-surface"; const textColor = isDanger ? "text-red-300" : "text-amber-300"; const btnClass = isDanger ? "bg-red-600 text-white hover:bg-red-700" : "bg-amber-600 text-white hover:bg-amber-700"; return html`
{ if (e.target === e.currentTarget) this.handleCancel(); }} >

${this.message}

${this.textareaPlaceholder ? html`` : ""}
`; } private handleConfirm() { this.dispatchEvent( new CustomEvent("confirm", { detail: { text: this.text } }), ); this.text = ""; } private handleCancel() { this.dispatchEvent(new CustomEvent("cancel")); this.text = ""; } }