This commit is contained in:
2026-04-11 02:08:07 +02:00
parent 290c87cec3
commit c4ebf5847b
14 changed files with 802 additions and 361 deletions

View File

@@ -6,7 +6,7 @@ import { val, ui } from "../core/utils.js";
* Tabs component
*
* daisyUI classes used:
* - tabs, tabs-box, tabs-lifted, tabs-bordered
* - tabs, tabs-box, tabs-lift, tabs-border
* - tab, tab-content
* - bg-base-100, border-base-300, p-6
*/
@@ -20,56 +20,43 @@ export const Tabs = (props) => {
if (idx !== -1 && idx !== activeIndex()) activeIndex(idx);
});
return Tag("div", { ...rest, class: "w-full" }, [
// 1. Tab List: Aplanamos los botones para que sean hijos directos
Tag("div", {
role: "tablist",
class: ui('tabs', className || 'tabs-box')
}, () => {
const list = itemsSignal();
return list.map((it, idx) => {
const isSelected = () => activeIndex() === idx;
const tab = Tag("button", {
role: "tab",
class: () => ui("tab", isSelected() ? "tab-active" : ""),
onclick: (e) => {
e.preventDefault();
if (!val(it.disabled)) {
if (it.onclick) it.onclick();
activeIndex(idx);
}
// Contenedor principal con las clases de DaisyUI
return Tag("div", { ...rest, class: ui('tabs', className) }, () => {
const list = itemsSignal();
const elements = [];
for (let i = 0; i < list.length; i++) {
const item = list[i];
const isActive = () => activeIndex() === i;
// Botón (tab)
const button = Tag("button", {
class: () => ui("tab", isActive() ? "tab-active" : ""),
onclick: (e) => {
e.preventDefault();
if (!val(item.disabled)) {
if (item.onclick) item.onclick();
activeIndex(i);
}
});
// Mantenemos el watch para el label por si es dinámico
Watch(() => {
const content = val(it.label);
if (content instanceof Node) {
tab.replaceChildren(content);
} else {
tab.textContent = String(content);
}
});
return tab;
}
});
}),
// 2. Tab Content: Aquí el display:contents no molesta tanto,
// pero lo aplanamos por consistencia
Tag("div", { class: "tab-panels" }, () => {
return itemsSignal().map((it, idx) => {
const isVisible = () => activeIndex() === idx;
return Tag("div", {
role: "tabpanel",
class: "tab-content bg-base-100 border-base-300 p-6",
style: () => isVisible() ? "display: block" : "display: none"
}, [
() => typeof it.content === "function" ? it.content() : it.content
]);
});
})
]);
// Asignar etiqueta (puede ser texto o nodo)
const label = val(item.label);
if (label instanceof Node) {
button.replaceChildren(label);
} else {
button.textContent = String(label);
}
elements.push(button);
// Contenido (tab-content) - debe ir inmediatamente después del botón
const panel = Tag("div", {
class: "tab-content bg-base-100 border-base-300 p-6",
style: () => isActive() ? "display: block" : "display: none"
}, () => val(item.content));
elements.push(panel);
}
return elements;
});
};