Versie 0.2.0

This commit is contained in:
Atreides Assets committed 2026-10-29 11:57:29 +01:00
commit e77d8fd373
495 files changed
+81026

No files matched your search

+109
View File
@@ -0,0 +1,109 @@
// Generated, do not edit. sha256:09856719543cb019750495d6ca12c5afc9eb3cc35cdf6a20a0f887e365cc177f
import { esc } from './escape.js';
function plainError(panel, err, id) {
console.error(`[tabs] ${id || ''}`, err);
panel.innerHTML = `<div class="alert alert-error">${esc(err && err.message ? err.message : String(err))}</div>`;
}
let onError = plainError;
export function configureTabs({ onError: handler = null } = {}) {
onError = handler || plainError;
}
export function rowLayout(count, content, room) {
const rows = count > 1 && content > room ? 2 : 1;
return { rows, cols: Math.ceil(count / rows) };
}
export function create(host, opts = {}) {
if (!host) return null;
const { items = [], render, onChange, size = '', syncOn = [], barHost = null } = opts;
const list = items.filter(it => it && (!it.when || it.when()));
let current = opts.active;
if (!list.some(it => it.id === current)) current = list[0] && list[0].id;
const bar = document.createElement('div');
bar.className = 'tabset' + (size === 'lg' ? ' tabset--lg' : '');
bar.setAttribute('role', 'tablist');
const panel = document.createElement('div');
panel.setAttribute('role', 'tabpanel');
if (host._tabsCleanup) host._tabsCleanup();
host.innerHTML = '';
if (barHost) { barHost.innerHTML = ''; barHost.append(bar); host.append(panel); }
else host.append(bar, panel);
function drawBar() {
bar.innerHTML = list.map(it => {
const on = it.id === current;
const dot = typeof it.dot === 'function' ? (it.dot() || '') : (it.dot || '');
return `<button class="tabset-tab${on ? ' is-on' : ''}" role="tab" aria-selected="${on}" data-tab="${it.id}">${it.label}${dot}</button>`;
}).join('');
bar.querySelectorAll('[data-tab]').forEach(b => { b.onclick = () => select(b.dataset.tab); });
if (size === 'lg') fitRows();
}
function fitRows() {
if (!bar.isConnected) return;
bar.classList.remove('tabset--rows');
const box = bar.getBoundingClientRect();
const last = bar.children[bar.children.length - 1];
const reach = last ? last.getBoundingClientRect().right - box.left : 0;
const { rows, cols } = rowLayout(list.length, Math.round(reach), Math.round(box.width));
if (rows < 2) return;
bar.classList.add('tabset--rows');
bar.style.setProperty('--tabset-cols', String(cols));
}
let seenWidth = -1;
const resize = size === 'lg' && typeof ResizeObserver === 'function'
? new ResizeObserver(entries => {
if (!bar.isConnected) { cleanup(); return; }
const width = entries[entries.length - 1].contentRect.width;
if (width === seenWidth) return;
seenWidth = width;
fitRows();
})
: null;
function drawPanel() {
panel.innerHTML = '';
if (!render) return;
try {
const r = render(current, panel);
if (r && typeof r.then === 'function') r.catch(err => onError(panel, err, current));
} catch (err) { onError(panel, err, current); }
}
function select(id, force) {
if (!force && id === current) return;
if (!list.some(it => it.id === id)) return;
current = id;
drawBar();
drawPanel();
if (onChange) onChange(id);
}
const onSync = () => { if (!bar.isConnected) { cleanup(); return; } drawBar(); };
function cleanup() {
syncOn.forEach(ev => document.removeEventListener(ev, onSync));
if (resize) resize.disconnect();
if (host._tabsCleanup === cleanup) host._tabsCleanup = null;
}
syncOn.forEach(ev => document.addEventListener(ev, onSync));
if (resize) resize.observe(bar);
host._tabsCleanup = cleanup;
drawBar();
drawPanel();
return {
el: host, bar, panel,
get active() { return current; },
select: id => select(id),
refresh: () => drawBar(),
redraw: () => drawPanel(),
destroy: cleanup,
};
}