89 lines
3.4 KiB
JavaScript
89 lines
3.4 KiB
JavaScript
// Generated, do not edit. sha256:2cb6efb613791caa2b77487d43b44b223a6a6e006b7a374e8ed1b4c6e8f50169
|
|
import { esc } from './escape.js';
|
|
|
|
const MOUNT = 'page-hint';
|
|
const INFO = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="11"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>';
|
|
|
|
let lead = '';
|
|
let empty = null;
|
|
|
|
export function configureHint({ lead: l = '', empty: e = null } = {}) {
|
|
lead = l || '';
|
|
empty = e;
|
|
}
|
|
|
|
function legend(title, content, className = '') {
|
|
return `
|
|
<div class="hint${className ? ' ' + className : ''}">
|
|
<button type="button" class="hint-btn" aria-label="${esc(title)}">${INFO}</button>
|
|
<div class="hint-panel" role="tooltip">
|
|
<div class="t-label">${esc(title)}</div>
|
|
${lead}
|
|
${content}
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
export function setPageHint(host, { title, rows = [] } = {}) {
|
|
const mount = document.getElementById(MOUNT);
|
|
if (!mount || !host?.isConnected) return;
|
|
mount.innerHTML = legend(title, rows.map(row).join(''));
|
|
watchFit(mount);
|
|
}
|
|
|
|
export function clearPageHint() {
|
|
const mount = document.getElementById(MOUNT);
|
|
if (!mount) return;
|
|
mount.innerHTML = empty ? legend(empty.title, '', empty.className || '') : '';
|
|
if (empty) watchFit(mount);
|
|
}
|
|
|
|
function watchFit(mount) {
|
|
if (mount.dataset.fitWatch) return;
|
|
mount.dataset.fitWatch = '1';
|
|
const fit = () => {
|
|
const panel = mount.querySelector('.hint-panel');
|
|
if (!panel) return;
|
|
panel.classList.remove('is-wide');
|
|
if (panel.scrollHeight > panel.clientHeight + 1) panel.classList.add('is-wide');
|
|
};
|
|
const close = () => {
|
|
const open = mount.querySelector('.hint.is-open');
|
|
open?.classList.remove('is-open');
|
|
open?.querySelector('.hint-btn')?.setAttribute('aria-expanded', 'false');
|
|
};
|
|
mount.addEventListener('pointerenter', fit);
|
|
mount.addEventListener('focusin', fit);
|
|
mount.addEventListener('click', (e) => {
|
|
const btn = e.target.closest?.('.hint-btn');
|
|
if (!btn) return;
|
|
const hint = btn.closest('.hint');
|
|
if (hint.classList.contains('is-open')) { close(); return; }
|
|
hint.classList.add('is-open');
|
|
btn.setAttribute('aria-expanded', 'true');
|
|
fit();
|
|
});
|
|
document.addEventListener('click', (e) => { if (!mount.contains(e.target)) close(); });
|
|
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') close(); });
|
|
}
|
|
|
|
function row(r) {
|
|
if (r && typeof r === 'object' && r.heading) return `<div class="hint-heading t-label">${r.heading}</div>`;
|
|
const text = typeof r === 'string' ? r : (r?.text ?? '');
|
|
const sample = typeof r === 'string' ? '' : (r?.sample ?? '');
|
|
return `<div class="hint-row"><span class="hint-sample">${sample}</span><span>${text}</span></div>`;
|
|
}
|
|
|
|
export const SAMPLES = Object.freeze({
|
|
line: '<span class="hint-line"></span>',
|
|
dashed: '<span class="hint-line is-dashed"></span>',
|
|
dot: '<span class="hint-dot"></span>',
|
|
dotOpen: '<span class="hint-dot is-open"></span>',
|
|
ring: '<span class="hint-ring"></span>',
|
|
cellFull: '<span class="hm-sample hm-full"></span>',
|
|
cellPart: '<span class="hm-sample hm-part"></span>',
|
|
cellLow: '<span class="hm-sample hm-low"></span>',
|
|
cellClosed: '<span class="hm-sample hm-closed"></span>',
|
|
cellNone: '<span class="hm-sample hm-none"></span>',
|
|
});
|