export interface ConfirmDialogOptions {
icon?: string;
title: string;
message: string;
confirmLabel?: string;
cancelLabel?: string;
danger?: boolean;
}
class ConfirmDialog extends HTMLElement {
private resolver: ((value: boolean) => void) | null = null;
connectedCallback(): void {
this.style.display = 'none';
this.innerHTML = `
`;
this.querySelector('.cd-backdrop')!.addEventListener('click', () => this.close(false));
this.querySelector('.cd-close')!.addEventListener('click', () => this.close(false));
document.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.key === 'Escape' && this.style.display !== 'none') this.close(false);
});
}
show(options: ConfirmDialogOptions): Promise {
console.log( "Show dialog" );
this.querySelector('.cd-icon')!.textContent = options.icon ?? '';
this.querySelector('.cd-title')!.textContent = options.title;
this.querySelector('.cd-message')!.textContent = options.message;
const footer = this.querySelector('.cd-footer')!;
footer.innerHTML = '';
if (options.cancelLabel) {
const cancel = document.createElement('button');
cancel.className = 'cd-btn cd-btn-cancel';
cancel.textContent = options.cancelLabel;
cancel.addEventListener('click', () => this.close(false));
footer.appendChild(cancel);
}
const confirm = document.createElement('button');
confirm.className = `cd-btn cd-btn-confirm${options.danger ? ' cd-btn-danger' : ''}`;
confirm.textContent = options.confirmLabel ?? 'OK';
confirm.addEventListener('click', () => this.close(true));
footer.appendChild(confirm);
this.style.display = '';
confirm.focus();
return new Promise(resolve => { this.resolver = resolve; });
}
private close(value: boolean): void {
this.style.display = 'none';
console.log( "Closing:", value );
if (this.resolver) { this.resolver(value); this.resolver = null; }
}
}
customElements.define('confirm-dialog', ConfirmDialog);
export function showConfirmDialog(options: ConfirmDialogOptions): Promise {
let dialog = document.querySelector('confirm-dialog') as ConfirmDialog | null;
if (!dialog) {
dialog = document.createElement('confirm-dialog') as ConfirmDialog;
document.body.appendChild(dialog);
}
return dialog.show(options);
}
// ── Input dialog ──────────────────────────────────────────────────────────────
export interface InputDialogOptions {
icon?: string;
title: string;
label: string;
defaultValue?: string;
confirmLabel?: string;
cancelLabel?: string;
}
class InputDialog extends HTMLElement {
private resolver: (( value: string | null ) => void) | null = null;
connectedCallback(): void {
this.style.display = 'none';
this.innerHTML = `
`;
this.querySelector( '.cd-backdrop' )!.addEventListener( 'click', () => this._close( null ) );
this.querySelector( '.cd-close' )!.addEventListener( 'click', () => this._close( null ) );
document.addEventListener( 'keydown', ( e: KeyboardEvent ) => {
if ( e.key === 'Escape' && this.style.display !== 'none' ) this._close( null );
if ( e.key === 'Enter' && this.style.display !== 'none' ) this._submit();
} );
}
show( options: InputDialogOptions ): Promise {
this.querySelector( '.cd-icon' )!.textContent = options.icon ?? '';
this.querySelector( '.cd-title' )!.textContent = options.title;
( this.querySelector( '.cd-input-label' ) as HTMLElement ).textContent = options.label;
const input = this.querySelector( '.cd-input-field' ) as HTMLInputElement;
input.value = options.defaultValue ?? '';
const footer = this.querySelector( '.cd-footer' )!;
footer.innerHTML = '';
const cancel = document.createElement( 'button' );
cancel.className = 'cd-btn cd-btn-cancel';
cancel.textContent = options.cancelLabel ?? 'Cancel';
cancel.addEventListener( 'click', () => this._close( null ) );
footer.appendChild( cancel );
const confirm = document.createElement( 'button' );
confirm.className = 'cd-btn cd-btn-confirm';
confirm.textContent = options.confirmLabel ?? 'OK';
confirm.addEventListener( 'click', () => this._submit() );
footer.appendChild( confirm );
this.style.display = '';
input.focus();
input.select();
return new Promise( resolve => { this.resolver = resolve; } );
}
private _submit(): void {
const value = ( this.querySelector( '.cd-input-field' ) as HTMLInputElement ).value.trim();
this._close( value || null );
}
private _close( value: string | null ): void {
this.style.display = 'none';
if ( this.resolver ) { this.resolver( value ); this.resolver = null; }
}
}
customElements.define( 'input-dialog', InputDialog );
export function showInputDialog( options: InputDialogOptions ): Promise {
let dialog = document.querySelector( 'input-dialog' ) as InputDialog | null;
if ( !dialog ) {
dialog = document.createElement( 'input-dialog' ) as InputDialog;
document.body.appendChild( dialog );
}
return dialog.show( options );
}