main
js 130 lines 3.74 KB
Raw
1 // Custom confirmation dialog. CSS in /css/modals.css
2
3 import { callJsExtensions } from "/js/extensions.js";
4
5 const DIALOG_TYPES = {
6 warning: { icon: 'warning', color: 'var(--color-warning, #f59e0b)' },
7 danger: { icon: 'error', color: 'var(--color-error, #ef4444)' },
8 info: { icon: 'info', color: 'var(--color-primary, #3b82f6)' }
9 };
10
11 export function showConfirmDialog(options) {
12 const {
13 title = 'Confirm',
14 message = '',
15 confirmText = 'Confirm',
16 cancelText = 'Cancel',
17 type = 'warning',
18 extensionContext = null,
19 } = options;
20
21 const typeConfig = DIALOG_TYPES[type] || DIALOG_TYPES.warning;
22
23 return new Promise((resolve) => {
24 // Create backdrop
25 const backdrop = document.createElement('div');
26 backdrop.className = 'confirm-dialog-backdrop';
27
28 // Create dialog
29 const dialog = document.createElement('div');
30 dialog.className = 'confirm-dialog';
31 dialog.innerHTML = `
32 <div class="confirm-dialog-header">
33 <x-icon class="confirm-dialog-icon" style="color: ${typeConfig.color}" name="${typeConfig.icon}"></x-icon>
34 <span class="confirm-dialog-title">${title}</span>
35 </div>
36 <div class="confirm-dialog-body">${message}</div>
37 <div class="confirm-dialog-footer">
38 <button class="button cancel confirm-dialog-cancel">${cancelText}</button>
39 <button class="button confirm confirm-dialog-confirm">${confirmText}</button>
40 </div>
41 `;
42
43 backdrop.appendChild(dialog);
44 document.body.appendChild(backdrop);
45
46 const titleElement = dialog.querySelector('.confirm-dialog-title');
47 const bodyElement = dialog.querySelector('.confirm-dialog-body');
48 const footerElement = dialog.querySelector('.confirm-dialog-footer');
49 const cancelButton = dialog.querySelector('.confirm-dialog-cancel');
50 const confirmButton = dialog.querySelector('.confirm-dialog-confirm');
51 let isClosed = false;
52
53 // Show with animation
54 const showDialog = () => {
55 requestAnimationFrame(() => {
56 backdrop.classList.add('visible');
57 cancelButton?.focus();
58 });
59 };
60
61 // Close handler
62 const close = (result) => {
63 if (isClosed) return;
64 isClosed = true;
65 backdrop.classList.remove('visible');
66 document.removeEventListener('keydown', handleKeydown);
67 setTimeout(() => {
68 backdrop.remove();
69 resolve(result);
70 }, 200);
71 };
72
73 // Event listeners
74 cancelButton.addEventListener('click', () => close(false));
75 confirmButton.addEventListener('click', () => close(true));
76 backdrop.addEventListener('click', (e) => e.target === backdrop && close(false));
77
78 // Keyboard handling
79 const handleKeydown = (e) => {
80 if (e.key === 'Escape') {
81 e.preventDefault();
82 close(false);
83 return;
84 }
85
86 if (e.key !== 'Enter') return;
87
88 const activeElement = document.activeElement;
89 if (
90 activeElement
91 && dialog.contains(activeElement)
92 && (
93 activeElement.tagName === 'BUTTON'
94 || activeElement.tagName === 'A'
95 || activeElement.tagName === 'INPUT'
96 || activeElement.tagName === 'TEXTAREA'
97 || activeElement.tagName === 'SELECT'
98 || activeElement.isContentEditable
99 )
100 ) {
101 return;
102 }
103
104 e.preventDefault();
105 close(true);
106 };
107 document.addEventListener('keydown', handleKeydown);
108
109 const extensionData = {
110 options,
111 dialog,
112 backdrop,
113 titleElement,
114 bodyElement,
115 footerElement,
116 confirmButton,
117 cancelButton,
118 close,
119 title,
120 message,
121 type,
122 confirmText,
123 cancelText,
124 extensionContext,
125 };
126
127 callJsExtensions('confirm_dialog_after_render', extensionData)
128 .finally(showDialog);
129 });
130 }