// components/Tabs.js import { $, Tag, Watch } from "../sigpro.js"; import { val, ui, getIcon } from "..//core/utils.js"; /** * Tabs component * * daisyUI classes used: * - tabs, tabs-box, tabs-lift, tabs-border * - tab, tab-content * - bg-base-100, border-base-300, p-6 */ export const Tabs = (props) => { const { items, class: className, onTabClose, ...rest } = props; const itemsSignal = typeof items === "function" ? items : () => items || []; const activeIndex = $(0); Watch(() => { const list = itemsSignal(); const idx = list.findIndex(it => val(it.active) === true); if (idx !== -1 && activeIndex() !== idx) { activeIndex(idx); } }); const removeTab = (indexToRemove, item) => { if (item.onClose) item.onClose(item); if (onTabClose) onTabClose(item, indexToRemove); 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 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 buttonBase = Tag("button", { class: () => ui("tab", activeIndex() === i ? "tab-active" : ""), onclick: (e) => { e.preventDefault(); if (!val(item.disabled)) { if (item.onclick) item.onclick(); activeIndex(i); } } }, buttonChildren); const button = item.tip ? Tag("div", { class: "tooltip", "data-tip": item.tip }, buttonBase) : buttonBase; elements.push(button); 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: () => activeIndex() === i ? "display: block" : "display: none" }, inner); elements.push(panel); } return elements; }); };