basecoat-cli 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/jinja/dialog.html.jinja +1 -1
- package/dist/assets/jinja/dropdown-menu.html.jinja +3 -3
- package/dist/assets/jinja/select.html.jinja +61 -49
- package/dist/assets/jinja/toast.html.jinja +2 -2
- package/dist/assets/js/all.js +796 -0
- package/dist/assets/js/all.min.js +1 -0
- package/dist/assets/js/dark-mode.js +10 -0
- package/dist/assets/js/dark-mode.min.js +1 -0
- package/dist/assets/js/dropdown-menu.js +128 -83
- package/dist/assets/js/dropdown-menu.min.js +1 -0
- package/dist/assets/js/popover.js +69 -26
- package/dist/assets/js/popover.min.js +1 -0
- package/dist/assets/js/select.js +195 -136
- package/dist/assets/js/select.min.js +1 -0
- package/dist/assets/js/sidebar.js +109 -24
- package/dist/assets/js/sidebar.min.js +1 -0
- package/dist/assets/js/tabs.js +68 -57
- package/dist/assets/js/tabs.min.js +1 -0
- package/dist/assets/js/toast.js +183 -62
- package/dist/assets/js/toast.min.js +1 -0
- package/dist/assets/nunjucks/dialog.njk +63 -79
- package/dist/assets/nunjucks/dropdown-menu.njk +29 -27
- package/dist/assets/nunjucks/popover.njk +11 -19
- package/dist/assets/nunjucks/select.njk +57 -37
- package/dist/assets/nunjucks/sidebar.njk +2 -5
- package/dist/assets/nunjucks/tabs.njk +7 -8
- package/dist/assets/nunjucks/toast.njk +45 -134
- package/dist/index.js +7 -7
- package/package.json +1 -1
- package/dist/assets/js/dialog.js +0 -54
package/dist/assets/js/toast.js
CHANGED
|
@@ -1,75 +1,196 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
(() => {
|
|
2
|
+
let toaster;
|
|
3
|
+
const toasts = new WeakMap();
|
|
4
|
+
let isPaused = false;
|
|
5
|
+
const ICONS = {
|
|
6
|
+
success: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
|
7
|
+
error: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
|
|
8
|
+
info: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
|
9
|
+
warning: '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function initToaster(toasterElement) {
|
|
13
|
+
if (toasterElement.dataset.toasterInitialized) return;
|
|
14
|
+
toaster = toasterElement;
|
|
15
|
+
|
|
16
|
+
toaster.addEventListener('mouseenter', pauseAllTimeouts);
|
|
17
|
+
toaster.addEventListener('mouseleave', resumeAllTimeouts);
|
|
18
|
+
toaster.addEventListener('click', (e) => {
|
|
19
|
+
const actionLink = e.target.closest('.toast footer a');
|
|
20
|
+
const actionButton = e.target.closest('.toast footer button');
|
|
21
|
+
if (actionLink || actionButton) {
|
|
22
|
+
closeToast(e.target.closest('.toast'));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
toaster.querySelectorAll('.toast:not([data-toast-initialized])').forEach(initToast);
|
|
27
|
+
toaster.dataset.toasterInitialized = 'true';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function initToast(element) {
|
|
31
|
+
if (element.dataset.toastInitialized) return;
|
|
32
|
+
|
|
33
|
+
const duration = parseInt(element.dataset.duration);
|
|
34
|
+
const timeoutDuration = duration !== -1
|
|
35
|
+
? duration || (element.dataset.category === 'error' ? 5000 : 3000)
|
|
36
|
+
: -1;
|
|
37
|
+
|
|
38
|
+
const state = {
|
|
39
|
+
remainingTime: timeoutDuration,
|
|
40
|
+
timeoutId: null,
|
|
41
|
+
startTime: null,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (timeoutDuration !== -1) {
|
|
45
|
+
if (isPaused) {
|
|
46
|
+
state.timeoutId = null;
|
|
47
|
+
} else {
|
|
48
|
+
state.startTime = Date.now();
|
|
49
|
+
state.timeoutId = setTimeout(() => closeToast(element), timeoutDuration);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
toasts.set(element, state);
|
|
53
|
+
|
|
54
|
+
element.dataset.toastInitialized = 'true';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function pauseAllTimeouts() {
|
|
58
|
+
if (isPaused) return;
|
|
59
|
+
|
|
60
|
+
isPaused = true;
|
|
61
|
+
|
|
62
|
+
toaster.querySelectorAll('.toast:not([aria-hidden="true"])').forEach(element => {
|
|
63
|
+
if (!toasts.has(element)) return;
|
|
64
|
+
|
|
65
|
+
const state = toasts.get(element);
|
|
66
|
+
if (state.timeoutId) {
|
|
67
|
+
clearTimeout(state.timeoutId);
|
|
68
|
+
state.timeoutId = null;
|
|
69
|
+
state.remainingTime -= Date.now() - state.startTime;
|
|
16
70
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function resumeAllTimeouts() {
|
|
75
|
+
if (!isPaused) return;
|
|
76
|
+
|
|
77
|
+
isPaused = false;
|
|
78
|
+
|
|
79
|
+
toaster.querySelectorAll('.toast:not([aria-hidden="true"])').forEach(element => {
|
|
80
|
+
if (!toasts.has(element)) return;
|
|
81
|
+
|
|
82
|
+
const state = toasts.get(element);
|
|
83
|
+
if (state.remainingTime !== -1 && !state.timeoutId) {
|
|
84
|
+
if (state.remainingTime > 0) {
|
|
85
|
+
state.startTime = Date.now();
|
|
86
|
+
state.timeoutId = setTimeout(() => closeToast(element), state.remainingTime);
|
|
22
87
|
} else {
|
|
23
|
-
|
|
88
|
+
closeToast(element);
|
|
24
89
|
}
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
pauseTimeout() {
|
|
28
|
-
clearTimeout(this.timeoutId);
|
|
29
|
-
this.timeoutId = null;
|
|
30
|
-
},
|
|
31
|
-
resumeTimeout(index) {
|
|
32
|
-
if (this.open && this.timeoutId === null) {
|
|
33
|
-
this.timeoutId = setTimeout(() => { this.close() }, this.timeoutDuration);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
close() {
|
|
37
|
-
this.pauseTimeout();
|
|
38
|
-
this.open = false;
|
|
39
|
-
this.$el.blur();
|
|
40
|
-
},
|
|
41
|
-
executeAction(actionString) {
|
|
42
|
-
if (actionString) {
|
|
43
|
-
Alpine.evaluate(this.$el, actionString);
|
|
44
90
|
}
|
|
45
|
-
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
46
93
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
['@mouseleave']() { this.$store.toaster.isPaused = false },
|
|
50
|
-
['@keydown.escape.prevent']() { this.close() },
|
|
51
|
-
[':aria-hidden']() { return !this.open }
|
|
52
|
-
},
|
|
53
|
-
}));
|
|
94
|
+
function closeToast(element) {
|
|
95
|
+
if (!toasts.has(element)) return;
|
|
54
96
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
97
|
+
const state = toasts.get(element);
|
|
98
|
+
clearTimeout(state.timeoutId);
|
|
99
|
+
toasts.delete(element);
|
|
100
|
+
|
|
101
|
+
if (document.activeElement) document.activeElement.blur();
|
|
102
|
+
element.setAttribute('aria-hidden', 'true');
|
|
103
|
+
element.addEventListener('transitionend', () => element.remove(), { once: true });
|
|
104
|
+
}
|
|
58
105
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
106
|
+
function executeAction(button, toast) {
|
|
107
|
+
const actionString = button.dataset.toastAction;
|
|
108
|
+
if (!actionString) return;
|
|
109
|
+
try {
|
|
110
|
+
const func = new Function('close', actionString);
|
|
111
|
+
func(() => closeToast(toast));
|
|
112
|
+
} catch (e) {
|
|
113
|
+
console.error('Error executing toast action:', e);
|
|
62
114
|
}
|
|
63
|
-
|
|
64
|
-
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function createToast(config) {
|
|
118
|
+
const {
|
|
119
|
+
category = 'info',
|
|
120
|
+
title,
|
|
121
|
+
description,
|
|
122
|
+
action,
|
|
123
|
+
cancel,
|
|
124
|
+
duration,
|
|
125
|
+
icon,
|
|
126
|
+
} = config;
|
|
127
|
+
|
|
128
|
+
const iconHtml = icon || (category && ICONS[category]) || '';
|
|
129
|
+
const titleHtml = title ? `<h2>${title}</h2>` : '';
|
|
130
|
+
const descriptionHtml = description ? `<p>${description}</p>` : '';
|
|
131
|
+
const actionHtml = action?.href
|
|
132
|
+
? `<a href="${action.href}" class="btn" data-toast-action>${action.label}</a>`
|
|
133
|
+
: action?.onclick
|
|
134
|
+
? `<button type="button" class="btn" data-toast-action onclick="${action.onclick}">${action.label}</button>`
|
|
135
|
+
: '';
|
|
136
|
+
const cancelHtml = cancel
|
|
137
|
+
? `<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${cancel?.onclick}">${cancel.label}</button>`
|
|
138
|
+
: '';
|
|
139
|
+
|
|
140
|
+
const footerHtml = actionHtml || cancelHtml ? `<footer>${actionHtml}${cancelHtml}</footer>` : '';
|
|
141
|
+
|
|
142
|
+
const html = `
|
|
143
|
+
<div
|
|
144
|
+
class="toast"
|
|
145
|
+
role="${category === 'error' ? 'alert' : 'status'}"
|
|
146
|
+
aria-atomic="true"
|
|
147
|
+
${category ? `data-category="${category}"` : ''}
|
|
148
|
+
${duration !== undefined ? `data-duration="${duration}"` : ''}
|
|
149
|
+
>
|
|
150
|
+
<div class="toast-content">
|
|
151
|
+
${iconHtml}
|
|
152
|
+
<section>
|
|
153
|
+
${titleHtml}
|
|
154
|
+
${descriptionHtml}
|
|
155
|
+
</section>
|
|
156
|
+
${footerHtml}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
`;
|
|
161
|
+
const template = document.createElement('template');
|
|
162
|
+
template.innerHTML = html.trim();
|
|
163
|
+
return template.content.firstChild;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const initialToaster = document.getElementById('toaster');
|
|
167
|
+
if (initialToaster) initToaster(initialToaster);
|
|
168
|
+
|
|
169
|
+
window.addEventListener('basecoat:toast', (e) => {
|
|
170
|
+
if (!toaster) {
|
|
171
|
+
console.error('Cannot create toast: toaster container not found on page.');
|
|
65
172
|
return;
|
|
66
173
|
}
|
|
174
|
+
const config = e.detail?.config || {};
|
|
175
|
+
const toastElement = createToast(config);
|
|
176
|
+
toaster.appendChild(toastElement);
|
|
177
|
+
});
|
|
67
178
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
179
|
+
const observer = new MutationObserver((mutations) => {
|
|
180
|
+
mutations.forEach((mutation) => {
|
|
181
|
+
mutation.addedNodes.forEach((node) => {
|
|
182
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
183
|
+
|
|
184
|
+
if (node.matches('#toaster')) {
|
|
185
|
+
initToaster(node);
|
|
186
|
+
}
|
|
72
187
|
|
|
73
|
-
|
|
188
|
+
if (toaster && node.matches('.toast:not([data-toast-initialized])')) {
|
|
189
|
+
initToast(node);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
74
193
|
});
|
|
75
|
-
|
|
194
|
+
|
|
195
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
196
|
+
})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(()=>{let t;const e=new WeakMap;let n=!1;const o={success:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',error:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',info:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',warning:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'};function i(e){e.dataset.toasterInitialized||(t=e,t.addEventListener("mouseenter",r),t.addEventListener("mouseleave",s),t.addEventListener("click",(t=>{const e=t.target.closest(".toast footer a"),n=t.target.closest(".toast footer button");(e||n)&&d(t.target.closest(".toast"))})),t.querySelectorAll(".toast:not([data-toast-initialized])").forEach(a),t.dataset.toasterInitialized="true")}function a(t){if(t.dataset.toastInitialized)return;const o=parseInt(t.dataset.duration),i=-1!==o?o||("error"===t.dataset.category?5e3:3e3):-1,a={remainingTime:i,timeoutId:null,startTime:null};-1!==i&&(n?a.timeoutId=null:(a.startTime=Date.now(),a.timeoutId=setTimeout((()=>d(t)),i))),e.set(t,a),t.dataset.toastInitialized="true"}function r(){n||(n=!0,t.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((t=>{if(!e.has(t))return;const n=e.get(t);n.timeoutId&&(clearTimeout(n.timeoutId),n.timeoutId=null,n.remainingTime-=Date.now()-n.startTime)})))}function s(){n&&(n=!1,t.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((t=>{if(!e.has(t))return;const n=e.get(t);-1===n.remainingTime||n.timeoutId||(n.remainingTime>0?(n.startTime=Date.now(),n.timeoutId=setTimeout((()=>d(t)),n.remainingTime)):d(t))})))}function d(t){if(!e.has(t))return;const n=e.get(t);clearTimeout(n.timeoutId),e.delete(t),document.activeElement&&document.activeElement.blur(),t.setAttribute("aria-hidden","true"),t.addEventListener("transitionend",(()=>t.remove()),{once:!0})}const c=document.getElementById("toaster");c&&i(c),window.addEventListener("basecoat:toast",(e=>{if(!t)return void console.error("Cannot create toast: toaster container not found on page.");const n=function(t){const{category:e="info",title:n,description:i,action:a,cancel:r,duration:s,icon:d}=t,c=d||e&&o[e]||"",l=n?`<h2>${n}</h2>`:"",u=i?`<p>${i}</p>`:"",h=a?.href?`<a href="${a.href}" class="btn" data-toast-action>${a.label}</a>`:a?.onclick?`<button type="button" class="btn" data-toast-action onclick="${a.onclick}">${a.label}</button>`:"",m=r?`<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${r?.onclick}">${r.label}</button>`:"",g=`\n <div\n class="toast"\n role="${"error"===e?"alert":"status"}"\n aria-atomic="true"\n ${e?`data-category="${e}"`:""}\n ${void 0!==s?`data-duration="${s}"`:""}\n >\n <div class="toast-content">\n ${c}\n <section>\n ${l}\n ${u}\n </section>\n ${h||m?`<footer>${h}${m}</footer>`:""}\n </div>\n </div>\n </div>\n `,v=document.createElement("template");return v.innerHTML=g.trim(),v.content.firstChild}(e.detail?.config||{});t.appendChild(n)}));new MutationObserver((e=>{e.forEach((e=>{e.addedNodes.forEach((e=>{e.nodeType===Node.ELEMENT_NODE&&(e.matches("#toaster")&&i(e),t&&e.matches(".toast:not([data-toast-initialized])")&&a(e))}))}))})).observe(document.body,{childList:!0,subtree:!0})})();
|
|
@@ -8,103 +8,87 @@
|
|
|
8
8
|
@param footer {string} [optional] - HTML content for the dialog footer.
|
|
9
9
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
10
10
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
11
|
-
@param
|
|
12
|
-
@param
|
|
13
|
-
@param
|
|
14
|
-
@param
|
|
11
|
+
@param dialog_attrs {object} [optional] - Additional HTML attributes for the dialog content article.
|
|
12
|
+
@param header_attrs {object} [optional] - Additional HTML attributes for the dialog header.
|
|
13
|
+
@param body_attrs {object} [optional] - Additional HTML attributes for the dialog body section.
|
|
14
|
+
@param footer_attrs {object} [optional] - Additional HTML attributes for the dialog footer.
|
|
15
15
|
@param open {boolean} [optional] [default=false] - Whether the dialog should be open initially.
|
|
16
16
|
@param close_button {boolean} [optional] [default=true] - Whether to include a close button.
|
|
17
17
|
@param close_on_overlay_click {boolean} [optional] [default=true] - Whether clicking the overlay closes the dialog.
|
|
18
18
|
#}
|
|
19
19
|
{% macro dialog(
|
|
20
|
-
id,
|
|
20
|
+
id=None,
|
|
21
21
|
trigger=None,
|
|
22
22
|
title=None,
|
|
23
23
|
description=None,
|
|
24
24
|
footer=None,
|
|
25
|
-
|
|
25
|
+
dialog_attrs={},
|
|
26
26
|
trigger_attrs={},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
content_footer_attrs={},
|
|
27
|
+
header_attrs={},
|
|
28
|
+
body_attrs={},
|
|
29
|
+
footer_attrs={},
|
|
31
30
|
open=false,
|
|
32
31
|
close_button=true,
|
|
33
32
|
close_on_overlay_click=true
|
|
34
33
|
) %}
|
|
35
|
-
|
|
34
|
+
{% set id = id or ("dialog-" + (range(100000, 999999) | random | string)) %}
|
|
35
|
+
{% if trigger %}
|
|
36
|
+
<button
|
|
37
|
+
type="button"
|
|
38
|
+
onclick="document.getElementById('{{ id }}').showModal()"
|
|
39
|
+
{% for key, value in trigger_attrs %}
|
|
40
|
+
{{ key }}="{{ value }}"
|
|
41
|
+
{% endfor %}
|
|
42
|
+
>
|
|
43
|
+
{{ trigger }}
|
|
44
|
+
</button>
|
|
45
|
+
{% endif %}
|
|
46
|
+
<dialog
|
|
36
47
|
id="{{ id }}"
|
|
37
|
-
x-data="dialog({{ 'true' if open else 'false' }}, {{ 'true' if close_on_overlay_click else 'false' }})"
|
|
38
|
-
x-bind="$main"
|
|
39
48
|
class="dialog"
|
|
40
|
-
{
|
|
49
|
+
aria-labelledby="{{ id }}-title"
|
|
50
|
+
{% if description %}aria-describedby="{{ id }}-description"{% endif %}
|
|
51
|
+
{% if close_on_overlay_click %}onclick="this.close()"{% endif %}
|
|
52
|
+
{% for key, value in dialog_attrs %}
|
|
41
53
|
{{ key }}="{{ value }}"
|
|
42
54
|
{% endfor %}
|
|
43
55
|
>
|
|
44
|
-
{% if
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
>
|
|
77
|
-
<h2 id="{{ id }}-title">{{ title | safe }}</h2>
|
|
78
|
-
<p>{{ description | safe }}</p>
|
|
79
|
-
</header>
|
|
80
|
-
{% endif %}
|
|
81
|
-
{% if caller %}
|
|
82
|
-
<section
|
|
83
|
-
{% for key, value in content_body_attrs %}
|
|
84
|
-
{{ key }}="{{ value }}"
|
|
85
|
-
{% endfor %}
|
|
86
|
-
>
|
|
87
|
-
{{ caller() }}
|
|
88
|
-
</section>
|
|
89
|
-
{% endif %}
|
|
90
|
-
{% if footer %}
|
|
91
|
-
<footer
|
|
92
|
-
{% for key, value in content_footer_attrs %}
|
|
93
|
-
{{ key }}="{{ value }}"
|
|
94
|
-
{% endfor %}
|
|
95
|
-
>
|
|
96
|
-
{{ footer | safe }}
|
|
97
|
-
</footer>
|
|
98
|
-
{% endif %}
|
|
99
|
-
{% if close_button %}
|
|
100
|
-
<button
|
|
101
|
-
@click="hide()"
|
|
102
|
-
aria-label="Close dialog"
|
|
103
|
-
>
|
|
56
|
+
<article {% if close_on_overlay_click %}onclick="event.stopPropagation()"{% endif %}>
|
|
57
|
+
{% if title or description %}
|
|
58
|
+
<header
|
|
59
|
+
{% for key, value in header_attrs %}
|
|
60
|
+
{{ key }}="{{ value }}"
|
|
61
|
+
{% endfor %}
|
|
62
|
+
>
|
|
63
|
+
<h2 id="{{ id }}-title">{{ title | safe }}</h2>
|
|
64
|
+
{% if description %}<p id="{{ id }}-description">{{ description | safe }}</p>{% endif %}
|
|
65
|
+
</header>
|
|
66
|
+
{% endif %}
|
|
67
|
+
{% if caller %}
|
|
68
|
+
<section
|
|
69
|
+
{% for key, value in body_attrs %}
|
|
70
|
+
{{ key }}="{{ value }}"
|
|
71
|
+
{% endfor %}
|
|
72
|
+
>
|
|
73
|
+
{{ caller() }}
|
|
74
|
+
</section>
|
|
75
|
+
{% endif %}
|
|
76
|
+
{% if footer %}
|
|
77
|
+
<footer
|
|
78
|
+
{% for key, value in footer_attrs %}
|
|
79
|
+
{{ key }}="{{ value }}"
|
|
80
|
+
{% endfor %}
|
|
81
|
+
>
|
|
82
|
+
{{ footer | safe }}
|
|
83
|
+
</footer>
|
|
84
|
+
{% endif %}
|
|
85
|
+
{% if close_button %}
|
|
86
|
+
<form method="dialog">
|
|
87
|
+
<button aria-label="Close dialog">
|
|
104
88
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
</
|
|
109
|
-
</
|
|
89
|
+
</button>
|
|
90
|
+
</form>
|
|
91
|
+
{% endif %}
|
|
92
|
+
</article>
|
|
93
|
+
</dialog>
|
|
110
94
|
{% endmacro %}
|
|
@@ -6,58 +6,59 @@
|
|
|
6
6
|
@param menu {array} [optional] - Array of menu items for the dropdown.
|
|
7
7
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
8
8
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
9
|
-
@param
|
|
9
|
+
@param popover_attrs {object} [optional] - Additional HTML attributes for the dropdown content div.
|
|
10
10
|
#}
|
|
11
11
|
{% macro dropdown_menu(
|
|
12
12
|
id=None,
|
|
13
|
-
trigger
|
|
14
|
-
|
|
13
|
+
trigger,
|
|
14
|
+
items=None,
|
|
15
15
|
main_attrs={},
|
|
16
16
|
trigger_attrs={},
|
|
17
|
-
|
|
17
|
+
popover_attrs={},
|
|
18
|
+
menu_attrs={}
|
|
18
19
|
) %}
|
|
20
|
+
{% set id = id or ("dropdown-menu-" + (range(100000, 999999) | random | string)) %}
|
|
21
|
+
|
|
19
22
|
<div
|
|
20
|
-
class="
|
|
21
|
-
x-data="dropdownMenu"
|
|
22
|
-
@click.away="open = false"
|
|
23
|
-
{% if id %}id="{{ id }}"{% endif %}
|
|
23
|
+
class="dropdown-menu {{ main_attrs.class }}"
|
|
24
24
|
{% for key, value in main_attrs %}
|
|
25
|
-
{% if key !=
|
|
25
|
+
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
26
26
|
{% endfor %}
|
|
27
27
|
>
|
|
28
|
-
{% if trigger %}
|
|
29
28
|
<button
|
|
30
29
|
type="button"
|
|
31
|
-
aria-haspopup="menu"
|
|
32
|
-
aria-expanded="false"
|
|
33
|
-
x-bind="$trigger"
|
|
34
|
-
{% if id %}
|
|
35
30
|
id="{{ id }}-trigger"
|
|
31
|
+
aria-haspopup="menu"
|
|
36
32
|
aria-controls="{{ id }}-menu"
|
|
37
|
-
|
|
33
|
+
aria-expanded="false"
|
|
38
34
|
{% for key, value in trigger_attrs %}
|
|
39
35
|
{{ key }}="{{ value }}"
|
|
40
36
|
{% endfor %}
|
|
41
37
|
>
|
|
42
38
|
{{ trigger | safe }}
|
|
43
39
|
</button>
|
|
44
|
-
{% endif %}
|
|
45
40
|
<div
|
|
41
|
+
id="{{ id }}"
|
|
46
42
|
data-popover
|
|
47
43
|
aria-hidden="true"
|
|
48
|
-
|
|
49
|
-
{% if id %}id="{{ id }}-menu"{% endif %}
|
|
50
|
-
{% for key, value in content_attrs %}
|
|
44
|
+
{% for key, value in popover_attrs %}
|
|
51
45
|
{{ key }}="{{ value }}"
|
|
52
46
|
{% endfor %}
|
|
53
47
|
>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
<div
|
|
49
|
+
role="menu"
|
|
50
|
+
id="{{ id }}-menu"
|
|
51
|
+
aria-labelledby="{{ id }}-trigger"
|
|
52
|
+
{% for key, value in menu_attrs %}
|
|
53
|
+
{{ key }}="{{ value }}"
|
|
54
|
+
{% endfor %}
|
|
55
|
+
>
|
|
56
|
+
{% if items %}
|
|
57
|
+
{{ render_dropdown_items(items, id ~ "-items" if id else "items") }}
|
|
57
58
|
{% else %}
|
|
58
59
|
{{ caller() if caller }}
|
|
59
60
|
{% endif %}
|
|
60
|
-
</
|
|
61
|
+
</div>
|
|
61
62
|
</div>
|
|
62
63
|
</div>
|
|
63
64
|
{% endmacro %}
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
{{ key }}="{{ value }}"
|
|
82
83
|
{% endfor %}
|
|
83
84
|
>
|
|
84
|
-
<div role="
|
|
85
|
+
<div role="presentation" id="{{ group_label_id }}">{{ item.label }}</div>
|
|
85
86
|
{{ render_dropdown_items(item.items, item_id) if item.items }}
|
|
86
87
|
</div>
|
|
87
88
|
{% elif item.type == "separator" %}
|
|
@@ -89,6 +90,7 @@
|
|
|
89
90
|
{% elif item.type == "item" or not item.type %}
|
|
90
91
|
{% if item.url %}
|
|
91
92
|
<a
|
|
93
|
+
id="{{ item_id }}"
|
|
92
94
|
role="menuitem"
|
|
93
95
|
href="{{ item.url }}"
|
|
94
96
|
{% for key, value in item.attrs %}
|
|
@@ -98,15 +100,15 @@
|
|
|
98
100
|
{{ item.label | safe }}
|
|
99
101
|
</a>
|
|
100
102
|
{% else %}
|
|
101
|
-
<
|
|
103
|
+
<div
|
|
104
|
+
id="{{ item_id }}"
|
|
102
105
|
role="menuitem"
|
|
103
|
-
type="button"
|
|
104
106
|
{% for key, value in item.attrs %}
|
|
105
107
|
{{ key }}="{{ value }}"
|
|
106
108
|
{% endfor %}
|
|
107
109
|
>
|
|
108
110
|
{{ item.label | safe }}
|
|
109
|
-
</
|
|
111
|
+
</div>
|
|
110
112
|
{% endif %}
|
|
111
113
|
{% endif %}
|
|
112
114
|
{% endfor %}
|
|
@@ -5,51 +5,43 @@
|
|
|
5
5
|
@param trigger {string} [optional] - HTML content for the element that triggers the popover.
|
|
6
6
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
7
7
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger element.
|
|
8
|
-
@param
|
|
8
|
+
@param popover_attrs {object} [optional] - Additional HTML attributes for the popover content div.
|
|
9
9
|
#}
|
|
10
10
|
{% macro popover(
|
|
11
11
|
id=None,
|
|
12
|
-
trigger
|
|
12
|
+
trigger,
|
|
13
13
|
main_attrs={},
|
|
14
14
|
trigger_attrs={},
|
|
15
|
-
|
|
15
|
+
popover_attrs={}
|
|
16
16
|
) %}
|
|
17
|
+
{% set id = id or ("popover-" + (range(100000, 999999) | random | string)) %}
|
|
18
|
+
|
|
17
19
|
<div
|
|
18
20
|
class="popover {{ main_attrs.class }}"
|
|
19
|
-
x-data="popover"
|
|
20
|
-
@click.away="open = false"
|
|
21
|
-
{% if id %}id="{{ id }}"{% endif %}
|
|
22
21
|
{% for key, value in main_attrs %}
|
|
23
22
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
24
23
|
{% endfor %}
|
|
25
24
|
>
|
|
26
|
-
{% if trigger %}
|
|
27
25
|
<button
|
|
26
|
+
id="{{ id }}-trigger"
|
|
28
27
|
type="button"
|
|
29
|
-
aria-haspopup="menu"
|
|
30
28
|
aria-expanded="false"
|
|
31
|
-
|
|
32
|
-
{% if id %}
|
|
33
|
-
id="{{ id }}-trigger"
|
|
34
|
-
aria-controls="{{ id }}-menu"
|
|
35
|
-
{% endif %}
|
|
29
|
+
aria-controls="{{ id }}"
|
|
36
30
|
{% for key, value in trigger_attrs %}
|
|
37
31
|
{{ key }}="{{ value }}"
|
|
38
32
|
{% endfor %}
|
|
39
33
|
>
|
|
40
34
|
{{ trigger | safe }}
|
|
41
35
|
</button>
|
|
42
|
-
{% endif %}
|
|
43
36
|
<div
|
|
37
|
+
id="{{ id }}"
|
|
44
38
|
data-popover
|
|
45
39
|
aria-hidden="true"
|
|
46
|
-
|
|
47
|
-
{% if id %}id="{{ id }}-menu"{% endif %}
|
|
48
|
-
{% for key, value in content_attrs %}
|
|
40
|
+
{% for key, value in popover_attrs %}
|
|
49
41
|
{{ key }}="{{ value }}"
|
|
50
42
|
{% endfor %}
|
|
51
|
-
>
|
|
43
|
+
>
|
|
52
44
|
{{ caller() if caller }}
|
|
53
45
|
</div>
|
|
54
46
|
</div>
|
|
55
|
-
{% endmacro %}
|
|
47
|
+
{% endmacro %}
|