Docs Updated
This commit is contained in:
@@ -12,8 +12,17 @@ import { ui } from "../core/utils.js";
|
||||
* - badge-outline, badge-soft, badge-dash
|
||||
* - badge-xs, badge-sm, badge-md, badge-lg
|
||||
*/
|
||||
export const Indicator = (props, children) =>
|
||||
$html("div", { class: "indicator" }, () => [
|
||||
children,
|
||||
props.value && $html("span", { class: ui('indicator-item badge', props.class) }, props.value),
|
||||
].filter(Boolean));
|
||||
export const Indicator = (props, children) => {
|
||||
const { value, class: className, ...rest } = props;
|
||||
|
||||
return $html("div", {
|
||||
...rest,
|
||||
class: "indicator"
|
||||
}, () => [
|
||||
// El indicador debe ir PRIMERO (antes que el children)
|
||||
value ? $html("span", {
|
||||
class: ui('indicator-item badge', className)
|
||||
}, () => typeof value === "function" ? value() : value) : null,
|
||||
children
|
||||
].filter(Boolean));
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
import { $html, $if } from "sigpro";
|
||||
|
||||
/** LOADING (Overlay Component) */
|
||||
export const Loading = (props) => {
|
||||
// Se espera un signal props.$show para controlar la visibilidad
|
||||
return $if(props.$show, () =>
|
||||
$html("div", {
|
||||
class: "fixed inset-0 z-[100] flex items-center justify-center backdrop-blur-sm bg-base-100/30"
|
||||
}, [
|
||||
$html("span", { class: "loading loading-spinner loading-lg text-primary" }),
|
||||
]),
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
// components/Modal.js
|
||||
import { $html, $watch } from "sigpro";
|
||||
import { ui, val } from "../core/utils.js";
|
||||
import { ui } from "../core/utils.js";
|
||||
import { tt } from "../core/i18n.js";
|
||||
import { Button } from "./Button.js";
|
||||
|
||||
@@ -15,45 +15,50 @@ import { Button } from "./Button.js";
|
||||
*/
|
||||
export const Modal = (props, children) => {
|
||||
const { class: className, title, buttons, open, ...rest } = props;
|
||||
const dialogRef = { current: null };
|
||||
let dialogElement = null;
|
||||
|
||||
$watch(() => {
|
||||
const dialog = dialogRef.current;
|
||||
if (!dialog) return;
|
||||
|
||||
if (val(open)) {
|
||||
if (!dialog.open) dialog.showModal();
|
||||
const handleOpen = () => {
|
||||
const isOpen = typeof open === "function" ? open() : open;
|
||||
if (!dialogElement) return;
|
||||
|
||||
if (isOpen) {
|
||||
if (!dialogElement.open) dialogElement.showModal();
|
||||
} else {
|
||||
if (dialog.open) dialog.close();
|
||||
if (dialogElement.open) dialogElement.close();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const close = (e) => {
|
||||
if (e && e.preventDefault) e.preventDefault();
|
||||
$watch(() => handleOpen());
|
||||
|
||||
const close = () => {
|
||||
if (typeof open === "function") open(false);
|
||||
};
|
||||
|
||||
return $html("dialog", {
|
||||
...rest,
|
||||
ref: dialogRef,
|
||||
ref: (el) => {
|
||||
dialogElement = el;
|
||||
if (el) handleOpen();
|
||||
},
|
||||
class: ui('modal', className),
|
||||
oncancel: () => typeof open === "function" && open(false)
|
||||
onclose: close,
|
||||
oncancel: close
|
||||
}, [
|
||||
$html("div", { class: "modal-box" }, [
|
||||
title ? $html("h3", { class: "text-lg font-bold mb-4" }, title) : null,
|
||||
title ? $html("h3", { class: "text-lg font-bold mb-4" }, () =>
|
||||
typeof title === "function" ? title() : title
|
||||
) : null,
|
||||
$html("div", { class: "py-2" }, [
|
||||
typeof children === "function" ? children() : children
|
||||
]),
|
||||
$html("div", { class: "modal-action flex gap-2" }, [
|
||||
...(Array.isArray(buttons) ? buttons : [buttons]).filter(Boolean),
|
||||
Button({ type: "button", onclick: close }, tt("close")()),
|
||||
]),
|
||||
$html("div", { class: "modal-action" }, [
|
||||
$html("form", { method: "dialog", class: "flex gap-2" }, [
|
||||
...(Array.isArray(buttons) ? buttons : [buttons]).filter(Boolean),
|
||||
Button({ type: "submit" }, tt("close")())
|
||||
])
|
||||
])
|
||||
]),
|
||||
$html("form", {
|
||||
method: "dialog",
|
||||
class: "modal-backdrop",
|
||||
onsubmit: close
|
||||
}, [
|
||||
$html("form", { method: "dialog", class: "modal-backdrop" }, [
|
||||
$html("button", {}, "close")
|
||||
])
|
||||
]);
|
||||
|
||||
@@ -15,7 +15,12 @@ export const Swap = (props) => {
|
||||
return $html("label", { ...rest, class: ui('swap', className) }, [
|
||||
$html("input", {
|
||||
type: "checkbox",
|
||||
checked: val(value)
|
||||
checked: () => val(value), // ← FUNCIÓN: se reevalúa cuando la señal cambia
|
||||
onclick: (e) => {
|
||||
if (typeof value === "function") {
|
||||
value(e.target.checked);
|
||||
}
|
||||
}
|
||||
}),
|
||||
$html("div", { class: "swap-on" }, on),
|
||||
$html("div", { class: "swap-off" }, off),
|
||||
|
||||
@@ -7,59 +7,64 @@ import { val, ui } from "../core/utils.js";
|
||||
*
|
||||
* daisyUI classes used:
|
||||
* - tabs, tabs-box, tabs-lifted, tabs-bordered
|
||||
* - tab, tab-active, tab-disabled
|
||||
* - flex, flex-col, gap-4, w-full, p-4
|
||||
* - tab, tab-content
|
||||
* - bg-base-100, border-base-300, p-6
|
||||
*/
|
||||
export const Tabs = (props) => {
|
||||
const { class: className, items, activeIndex = $(0), ...rest } = props;
|
||||
|
||||
const { items, class: className, ...rest } = props;
|
||||
const itemsSignal = typeof items === "function" ? items : () => items || [];
|
||||
const name = `tabs-${Math.random().toString(36).slice(2, 9)}`;
|
||||
|
||||
// Si no se provee activeIndex, creamos uno interno
|
||||
const internalActive = $(0);
|
||||
const currentActive = activeIndex !== undefined ? activeIndex : internalActive;
|
||||
|
||||
const handleTabClick = (idx, onClick) => (e) => {
|
||||
if (typeof currentActive === "function") {
|
||||
currentActive(idx);
|
||||
}
|
||||
onClick?.(e);
|
||||
// Encontrar el índice activo
|
||||
const getActiveIndex = () => {
|
||||
const arr = itemsSignal();
|
||||
const idx = arr.findIndex(it => val(it.active) === true);
|
||||
return idx === -1 ? 0 : idx;
|
||||
};
|
||||
|
||||
return $html("div", { ...rest, class: "flex flex-col gap-4 w-full" }, [
|
||||
$html(
|
||||
"div",
|
||||
{
|
||||
role: "tablist",
|
||||
class: ui('tabs tabs-box', className),
|
||||
},
|
||||
$for(
|
||||
itemsSignal,
|
||||
(it, idx) => {
|
||||
const isActive = val(it.active) ?? (currentActive() === idx);
|
||||
|
||||
return $html(
|
||||
"a",
|
||||
{
|
||||
role: "tab",
|
||||
class: () => ui('tab', isActive ? 'tab-active' : '', val(it.disabled) ? 'tab-disabled' : ''),
|
||||
onclick: !val(it.disabled) ? handleTabClick(idx, it.onclick) : undefined,
|
||||
},
|
||||
it.label,
|
||||
);
|
||||
},
|
||||
(t, idx) => t.label + idx,
|
||||
),
|
||||
),
|
||||
() => {
|
||||
const activeItem = itemsSignal().find((it, idx) =>
|
||||
val(it.active) ?? (currentActive() === idx)
|
||||
);
|
||||
if (!activeItem) return null;
|
||||
const content = val(activeItem.content);
|
||||
return $html("div", { class: "p-4" }, [
|
||||
typeof content === "function" ? content() : content
|
||||
]);
|
||||
},
|
||||
const activeIndex = $(getActiveIndex);
|
||||
|
||||
const updateActiveIndex = () => {
|
||||
const newIndex = getActiveIndex();
|
||||
if (newIndex !== activeIndex()) activeIndex(newIndex);
|
||||
};
|
||||
|
||||
$watch(() => updateActiveIndex());
|
||||
|
||||
return $html("div", {
|
||||
...rest,
|
||||
class: ui('tabs', className || 'tabs-box')
|
||||
}, [
|
||||
$for(itemsSignal, (it, idx) => {
|
||||
const isChecked = () => activeIndex() === idx;
|
||||
const getLabelText = () => {
|
||||
const label = typeof it.label === "function" ? it.label() : it.label;
|
||||
return typeof label === "string" ? label : `Tab ${idx + 1}`;
|
||||
};
|
||||
|
||||
return [
|
||||
$html("input", {
|
||||
type: "radio",
|
||||
name: name,
|
||||
class: "tab",
|
||||
"aria-label": getLabelText(),
|
||||
checked: isChecked, // ← función reactiva, no string hardcodeado
|
||||
disabled: () => val(it.disabled),
|
||||
onchange: (e) => {
|
||||
if (e.target.checked && !val(it.disabled)) {
|
||||
if (it.onclick) it.onclick();
|
||||
if (typeof it.active === "function") it.active(true);
|
||||
activeIndex(idx);
|
||||
}
|
||||
}
|
||||
}),
|
||||
$html("div", {
|
||||
class: "tab-content bg-base-100 border-base-300 p-6",
|
||||
style: () => isChecked() ? "display: block" : "display: none"
|
||||
}, [
|
||||
typeof it.content === "function" ? it.content() : it.content
|
||||
])
|
||||
];
|
||||
}, (it, idx) => idx)
|
||||
]);
|
||||
};
|
||||
@@ -21,6 +21,8 @@ export const Timeline = (props) => {
|
||||
error: "icon-[lucide--alert-circle]",
|
||||
};
|
||||
|
||||
const itemsSource = typeof items === "function" ? items : () => items || [];
|
||||
|
||||
return $html(
|
||||
"ul",
|
||||
{
|
||||
@@ -30,23 +32,23 @@ export const Timeline = (props) => {
|
||||
},
|
||||
[
|
||||
$for(
|
||||
items,
|
||||
itemsSource,
|
||||
(item, i) => {
|
||||
const isFirst = i === 0;
|
||||
const isLast = i === val(items).length - 1;
|
||||
const isLast = i === itemsSource().length - 1;
|
||||
const itemType = item.type || "success";
|
||||
const renderSlot = (content) => (typeof content === "function" ? content() : content);
|
||||
|
||||
return $html("li", { class: "flex-1" }, [
|
||||
!isFirst ? $html("hr", { class: item.completed ? "bg-primary" : "" }) : null,
|
||||
$html("div", { class: "timeline-start" }, [renderSlot(item.title)]),
|
||||
$html("div", { class: "timeline-middle" }, [
|
||||
!isFirst ? $html("hr", { class: () => item.completed ? "bg-primary" : "" }) : null,
|
||||
$html("div", { class: "timeline-start" }, () => renderSlot(item.title)),
|
||||
$html("div", { class: "timeline-middle" }, () => [
|
||||
item.icon
|
||||
? getIcon(item.icon)
|
||||
: getIcon(iconMap[itemType] || iconMap.success)
|
||||
]),
|
||||
$html("div", { class: "timeline-end timeline-box shadow-sm" }, [renderSlot(item.detail)]),
|
||||
!isLast ? $html("hr", { class: item.completed ? "bg-primary" : "" }) : null,
|
||||
$html("div", { class: "timeline-end timeline-box shadow-sm" }, () => renderSlot(item.detail)),
|
||||
!isLast ? $html("hr", { class: () => item.completed ? "bg-primary" : "" }) : null,
|
||||
]);
|
||||
},
|
||||
(item, i) => item.id || i,
|
||||
|
||||
@@ -15,7 +15,6 @@ import * as IndicatorModule from './Indicator.js';
|
||||
import * as InputModule from './Input.js';
|
||||
import * as LabelModule from './Label.js';
|
||||
import * as ListModule from './List.js';
|
||||
import * as LoadingModule from './Loading.js';
|
||||
import * as MenuModule from './Menu.js';
|
||||
import * as ModalModule from './Modal.js';
|
||||
import * as NavbarModule from './Navbar.js';
|
||||
@@ -49,7 +48,6 @@ export * from './Indicator.js';
|
||||
export * from './Input.js';
|
||||
export * from './Label.js';
|
||||
export * from './List.js';
|
||||
export * from './Loading.js';
|
||||
export * from './Menu.js';
|
||||
export * from './Modal.js';
|
||||
export * from './Navbar.js';
|
||||
@@ -84,7 +82,6 @@ const Components = {
|
||||
...InputModule,
|
||||
...LabelModule,
|
||||
...ListModule,
|
||||
...LoadingModule,
|
||||
...MenuModule,
|
||||
...ModalModule,
|
||||
...NavbarModule,
|
||||
|
||||
Reference in New Issue
Block a user