Tabs Con pestañas cerrables
This commit is contained in:
@@ -15,51 +15,91 @@ export const Tabs = (props) => {
|
||||
const itemsSignal = typeof items === "function" ? items : () => items || [];
|
||||
const activeIndex = $(0);
|
||||
|
||||
// Sincroniza con active:true solo cuando cambia la lista de items
|
||||
Watch(() => {
|
||||
const idx = itemsSignal().findIndex(it => val(it.active) === true);
|
||||
if (idx !== -1 && idx !== activeIndex()) activeIndex(idx);
|
||||
const list = itemsSignal();
|
||||
const idx = list.findIndex(it => val(it.active) === true);
|
||||
if (idx !== -1 && activeIndex() !== idx) {
|
||||
activeIndex(idx);
|
||||
}
|
||||
});
|
||||
|
||||
// Contenedor principal con las clases de DaisyUI
|
||||
const removeTab = (indexToRemove, item) => {
|
||||
if (item.onClose) item.onClose();
|
||||
const currentItems = itemsSignal();
|
||||
const newItems = currentItems.filter((_, idx) => idx !== indexToRemove);
|
||||
const isWritableSignal = typeof items === "function" && !items._isComputed;
|
||||
if (!isWritableSignal) {
|
||||
console.warn("Tabs: items must be a writable signal to support closable tabs");
|
||||
return;
|
||||
}
|
||||
items(newItems);
|
||||
if (newItems.length === 0) return;
|
||||
let newActive = activeIndex();
|
||||
if (indexToRemove < newActive) newActive--;
|
||||
else if (indexToRemove === newActive) newActive = Math.min(newActive, newItems.length - 1);
|
||||
activeIndex(newActive);
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
// --- Botón ---
|
||||
const label = val(item.label);
|
||||
const labelNode = label instanceof Node ? label : document.createTextNode(String(label));
|
||||
const buttonChildren = [];
|
||||
|
||||
if (item.closable) {
|
||||
const closeIcon = getIcon("icon-[lucide--x]");
|
||||
closeIcon.classList.add("w-3.5", "h-3.5", "ml-2", "cursor-pointer", "hover:opacity-70");
|
||||
closeIcon.onclick = (e) => {
|
||||
e.stopPropagation();
|
||||
removeTab(i, item);
|
||||
};
|
||||
const wrapper = Tag("span", { class: "flex items-center" }, [labelNode, closeIcon]);
|
||||
buttonChildren.push(wrapper);
|
||||
} else {
|
||||
buttonChildren.push(labelNode);
|
||||
}
|
||||
|
||||
const button = Tag("button", {
|
||||
class: () => ui("tab", isActive() ? "tab-active" : ""),
|
||||
class: () => {
|
||||
const isActive = activeIndex() === i;
|
||||
return ui("tab", isActive ? "tab-active" : "");
|
||||
},
|
||||
onclick: (e) => {
|
||||
e.preventDefault();
|
||||
if (!val(item.disabled)) {
|
||||
if (item.onclick) item.onclick();
|
||||
activeIndex(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Asignar etiqueta (puede ser texto o nodo)
|
||||
const label = val(item.label);
|
||||
if (label instanceof Node) {
|
||||
button.replaceChildren(label);
|
||||
} else {
|
||||
button.textContent = String(label);
|
||||
}
|
||||
},
|
||||
title: item.tip || ""
|
||||
}, buttonChildren);
|
||||
elements.push(button);
|
||||
|
||||
// Contenido (tab-content) - borde exterior estático
|
||||
|
||||
// --- Panel ---
|
||||
let contentNode;
|
||||
const rawContent = val(item.content);
|
||||
if (typeof rawContent === "function") {
|
||||
contentNode = rawContent();
|
||||
} else if (rawContent instanceof Node) {
|
||||
contentNode = rawContent;
|
||||
} else {
|
||||
contentNode = document.createTextNode(String(rawContent));
|
||||
}
|
||||
|
||||
const inner = Tag("div", { class: "tab-content-inner" }, contentNode);
|
||||
const panel = Tag("div", {
|
||||
class: "tab-content bg-base-100 border-base-300 p-6",
|
||||
style: () => isActive() ? "display: block" : "display: none"
|
||||
}, [
|
||||
// Contenedor interno con animación
|
||||
Tag("div", { class: "tab-content-inner" }, () => val(item.content))
|
||||
]);
|
||||
style: () => activeIndex() === i ? "display: block" : "display: none"
|
||||
}, inner);
|
||||
elements.push(panel);
|
||||
}
|
||||
|
||||
return elements;
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user