Files
sigpro-ui/dist/sigpro-ui.esm.js
2026-04-04 18:30:52 +02:00

1909 lines
61 KiB
JavaScript

var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, {
get: all[name],
enumerable: true,
configurable: true,
set: (newValue) => all[name] = () => newValue
});
};
// src/sigpro.js
var activeEffect = null;
var currentOwner = null;
var effectQueue = new Set;
var isFlushing = false;
var MOUNTED_NODES = new WeakMap;
var flush = () => {
if (isFlushing)
return;
isFlushing = true;
while (effectQueue.size > 0) {
const sorted = Array.from(effectQueue).sort((a, b) => (a.depth || 0) - (b.depth || 0));
effectQueue.clear();
for (const eff of sorted)
if (!eff._deleted)
eff();
}
isFlushing = false;
};
var track = (subs) => {
if (activeEffect && !activeEffect._deleted) {
subs.add(activeEffect);
activeEffect._deps.add(subs);
}
};
var trigger = (subs) => {
for (const eff of subs) {
if (eff === activeEffect || eff._deleted)
continue;
if (eff._isComputed) {
eff.markDirty();
if (eff._subs)
trigger(eff._subs);
} else {
effectQueue.add(eff);
}
}
if (!isFlushing)
queueMicrotask(flush);
};
var sweep = (node) => {
if (node._cleanups) {
node._cleanups.forEach((f) => f());
node._cleanups.clear();
}
node.childNodes?.forEach(sweep);
};
var _view = (fn) => {
const cleanups = new Set;
const prev = currentOwner;
const container = document.createElement("div");
container.style.display = "contents";
currentOwner = { cleanups };
try {
const res = fn({ onCleanup: (f) => cleanups.add(f) });
const process = (n) => {
if (!n)
return;
if (n._isRuntime) {
cleanups.add(n.destroy);
container.appendChild(n.container);
} else if (Array.isArray(n))
n.forEach(process);
else
container.appendChild(n instanceof Node ? n : document.createTextNode(String(n)));
};
process(res);
} finally {
currentOwner = prev;
}
return {
_isRuntime: true,
container,
destroy: () => {
cleanups.forEach((f) => f());
sweep(container);
container.remove();
}
};
};
var $ = (initial, key = null) => {
if (typeof initial === "function") {
const subs2 = new Set;
let cached, dirty = true;
const effect = () => {
if (effect._deleted)
return;
effect._deps.forEach((s) => s.delete(effect));
effect._deps.clear();
const prev = activeEffect;
activeEffect = effect;
try {
const val = initial();
if (!Object.is(cached, val) || dirty) {
cached = val;
dirty = false;
trigger(subs2);
}
} finally {
activeEffect = prev;
}
};
effect._deps = new Set;
effect._isComputed = true;
effect._subs = subs2;
effect._deleted = false;
effect.markDirty = () => dirty = true;
effect.stop = () => {
effect._deleted = true;
effect._deps.forEach((s) => s.delete(effect));
subs2.clear();
};
if (currentOwner)
currentOwner.cleanups.add(effect.stop);
return () => {
if (dirty)
effect();
track(subs2);
return cached;
};
}
let value = initial;
if (key) {
try {
const saved = localStorage.getItem(key);
if (saved !== null)
value = JSON.parse(saved);
} catch (e) {
console.warn("SigPro: LocalStorage locked", e);
}
}
const subs = new Set;
return (...args) => {
if (args.length) {
const next = typeof args[0] === "function" ? args[0](value) : args[0];
if (!Object.is(value, next)) {
value = next;
if (key)
localStorage.setItem(key, JSON.stringify(value));
trigger(subs);
}
}
track(subs);
return value;
};
};
var $watch2 = (target, fn) => {
const isExplicit = Array.isArray(target);
const callback = isExplicit ? fn : target;
const depsInput = isExplicit ? target : null;
if (typeof callback !== "function")
return () => {};
const owner = currentOwner;
const runner = () => {
if (runner._deleted)
return;
runner._deps.forEach((s) => s.delete(runner));
runner._deps.clear();
runner._cleanups.forEach((c) => c());
runner._cleanups.clear();
const prevEffect = activeEffect;
const prevOwner = currentOwner;
activeEffect = runner;
currentOwner = { cleanups: runner._cleanups };
runner.depth = prevEffect ? prevEffect.depth + 1 : 0;
try {
if (isExplicit) {
activeEffect = null;
callback();
activeEffect = runner;
depsInput.forEach((d) => typeof d === "function" && d());
} else {
callback();
}
} finally {
activeEffect = prevEffect;
currentOwner = prevOwner;
}
};
runner._deps = new Set;
runner._cleanups = new Set;
runner._deleted = false;
runner.stop = () => {
if (runner._deleted)
return;
runner._deleted = true;
effectQueue.delete(runner);
runner._deps.forEach((s) => s.delete(runner));
runner._cleanups.forEach((c) => c());
if (owner)
owner.cleanups.delete(runner.stop);
};
if (owner)
owner.cleanups.add(runner.stop);
runner();
return runner.stop;
};
var $html2 = (tag, props = {}, content = []) => {
if (props instanceof Node || Array.isArray(props) || typeof props !== "object") {
content = props;
props = {};
}
const svgTags = ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "g", "defs", "text", "tspan", "use"];
const isSVG = svgTags.includes(tag);
const el = isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag);
const _sanitize = (key, val) => (key === "src" || key === "href") && String(val).toLowerCase().includes("javascript:") ? "#" : val;
el._cleanups = new Set;
const boolAttrs = ["disabled", "checked", "required", "readonly", "selected", "multiple", "autofocus"];
for (let [key, val] of Object.entries(props)) {
if (key === "ref") {
typeof val === "function" ? val(el) : val.current = el;
continue;
}
const isSignal = typeof val === "function", isInput = ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName), isBindAttr = key === "value" || key === "checked";
if (isInput && isBindAttr && isSignal) {
el._cleanups.add($watch2(() => {
const currentVal = val();
if (el[key] !== currentVal)
el[key] = currentVal;
}));
const eventName = key === "checked" ? "change" : "input", handler = (event) => val(event.target[key]);
el.addEventListener(eventName, handler);
el._cleanups.add(() => el.removeEventListener(eventName, handler));
} else if (key.startsWith("on")) {
const eventName = key.slice(2).toLowerCase().split(".")[0], handler = (event) => val(event);
el.addEventListener(eventName, handler);
el._cleanups.add(() => el.removeEventListener(eventName, handler));
} else if (isSignal) {
el._cleanups.add($watch2(() => {
const currentVal = _sanitize(key, val());
if (key === "class") {
el.className = currentVal || "";
} else if (boolAttrs.includes(key)) {
if (currentVal) {
el.setAttribute(key, "");
el[key] = true;
} else {
el.removeAttribute(key);
el[key] = false;
}
} else {
if (currentVal == null) {
el.removeAttribute(key);
} else if (isSVG && typeof currentVal === "number") {
el.setAttribute(key, currentVal);
} else {
el.setAttribute(key, currentVal);
}
}
}));
} else {
if (boolAttrs.includes(key)) {
if (val) {
el.setAttribute(key, "");
el[key] = true;
} else {
el.removeAttribute(key);
el[key] = false;
}
} else {
el.setAttribute(key, _sanitize(key, val));
}
}
}
const append = (child) => {
if (Array.isArray(child))
return child.forEach(append);
if (child instanceof Node) {
el.appendChild(child);
} else if (typeof child === "function") {
const marker = document.createTextNode("");
el.appendChild(marker);
let nodes = [];
el._cleanups.add($watch2(() => {
const res = child(), next = (Array.isArray(res) ? res : [res]).map((i) => i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? ""));
nodes.forEach((n) => {
sweep?.(n);
n.remove();
});
next.forEach((n) => marker.parentNode?.insertBefore(n, marker));
nodes = next;
}));
} else
el.appendChild(document.createTextNode(child ?? ""));
};
append(content);
return el;
};
var $if = (condition, thenVal, otherwiseVal = null, transition = null) => {
const marker = document.createTextNode("");
const container = $html2("div", { style: "display:contents" }, [marker]);
let current = null, last = null;
$watch2(() => {
const state = !!(typeof condition === "function" ? condition() : condition);
if (state === last)
return;
last = state;
if (current && !state && transition?.out) {
transition.out(current.container, () => {
current.destroy();
current = null;
});
} else {
if (current)
current.destroy();
current = null;
}
if (state || !state && otherwiseVal) {
const branch = state ? thenVal : otherwiseVal;
if (branch) {
current = _view(() => typeof branch === "function" ? branch() : branch);
container.insertBefore(current.container, marker);
if (state && transition?.in)
transition.in(current.container);
}
}
});
return container;
};
$if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition === "function" ? condition() : condition), thenVal, otherwiseVal);
var $for = (source, render, keyFn, tag = "div", props = { style: "display:contents" }) => {
const marker = document.createTextNode("");
const container = $html2(tag, props, [marker]);
let cache = new Map;
$watch2(() => {
const items = (typeof source === "function" ? source() : source) || [];
const newCache = new Map;
const newOrder = [];
for (let i = 0;i < items.length; i++) {
const item = items[i];
const key = keyFn ? keyFn(item, i) : i;
let run = cache.get(key);
if (!run) {
run = _view(() => render(item, i));
} else {
cache.delete(key);
}
newCache.set(key, run);
newOrder.push(key);
}
cache.forEach((run) => {
run.destroy();
run.container.remove();
});
let anchor = marker;
for (let i = newOrder.length - 1;i >= 0; i--) {
const run = newCache.get(newOrder[i]);
if (run.container.nextSibling !== anchor) {
container.insertBefore(run.container, anchor);
}
anchor = run.container;
}
cache = newCache;
});
return container;
};
var $router = (routes) => {
const sPath = $(window.location.hash.replace(/^#/, "") || "/");
window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/"));
const outlet = $html2("div", { class: "router-outlet" });
let current = null;
$watch2([sPath], async () => {
const path = sPath();
const route = routes.find((r) => {
const rp = r.path.split("/").filter(Boolean), pp = path.split("/").filter(Boolean);
return rp.length === pp.length && rp.every((p, i) => p.startsWith(":") || p === pp[i]);
}) || routes.find((r) => r.path === "*");
if (route) {
let comp = route.component;
if (typeof comp === "function" && comp.toString().includes("import")) {
comp = (await comp()).default || await comp();
}
const params = {};
route.path.split("/").filter(Boolean).forEach((p, i) => {
if (p.startsWith(":"))
params[p.slice(1)] = path.split("/").filter(Boolean)[i];
});
if (current)
current.destroy();
if ($router.params)
$router.params(params);
current = _view(() => {
try {
return typeof comp === "function" ? comp(params) : comp;
} catch (e) {
return $html2("div", { class: "p-4 text-error" }, "Error loading view");
}
});
outlet.appendChild(current.container);
}
});
return outlet;
};
$router.params = $({});
$router.to = (path) => window.location.hash = path.replace(/^#?\/?/, "#/");
$router.back = () => window.history.back();
$router.path = () => window.location.hash.replace(/^#/, "") || "/";
var $mount = (component, target) => {
const el = typeof target === "string" ? document.querySelector(target) : target;
if (!el)
return;
if (MOUNTED_NODES.has(el))
MOUNTED_NODES.get(el).destroy();
const instance = _view(typeof component === "function" ? component : () => component);
el.replaceChildren(instance.container);
MOUNTED_NODES.set(el, instance);
return instance;
};
var Fragment = ({ children }) => children;
var SigProCore = { $, $watch: $watch2, $html: $html2, $if, $for, $router, $mount, Fragment };
if (typeof window !== "undefined") {
const install = (registry) => {
Object.keys(registry).forEach((key) => {
window[key] = registry[key];
});
const tags = `div span p h1 h2 h3 h4 h5 h6 br hr section article aside nav main header footer address ul ol li dl dt dd a em strong small i b u mark time sub sup pre code blockquote details summary dialog form label input textarea select button option fieldset legend table thead tbody tfoot tr th td caption img video audio canvas svg iframe picture source progress meter`.split(/\s+/);
tags.forEach((tagName) => {
const helperName = tagName.charAt(0).toUpperCase() + tagName.slice(1);
if (!(helperName in window)) {
window[helperName] = (props, content) => $html2(tagName, props, content);
}
});
window.Fragment = Fragment;
window.SigPro = Object.freeze(registry);
};
install(SigProCore);
}
// src/components/index.js
var exports_components = {};
__export(exports_components, {
default: () => components_default,
Tooltip: () => Tooltip,
Toast: () => Toast,
Timeline: () => Timeline,
Tabs: () => Tabs,
Table: () => Table,
Swap: () => Swap,
Stat: () => Stat,
Stack: () => Stack,
Select: () => Select,
Rating: () => Rating,
Range: () => Range,
Radio: () => Radio,
Navbar: () => Navbar,
Modal: () => Modal,
Menu: () => Menu,
List: () => List,
Label: () => Label,
Input: () => Input,
Indicator: () => Indicator,
Fileinput: () => Fileinput,
Fieldset: () => Fieldset,
Fab: () => Fab,
Dropdown: () => Dropdown,
Drawer: () => Drawer,
Datepicker: () => Datepicker,
Colorpicker: () => Colorpicker,
Checkbox: () => Checkbox,
Button: () => Button,
Badge: () => Badge,
Autocomplete: () => Autocomplete,
Alert: () => Alert,
Accordion: () => Accordion
});
// src/components/Accordion.js
var exports_Accordion = {};
__export(exports_Accordion, {
Accordion: () => Accordion
});
// src/core/utils.js
var exports_utils = {};
__export(exports_utils, {
val: () => val,
ui: () => ui,
getIcon: () => getIcon
});
var val = (t) => typeof t === "function" ? t() : t;
var ui = (baseClass, additionalClassOrFn) => typeof additionalClassOrFn === "function" ? () => `${baseClass} ${additionalClassOrFn() || ""}`.trim() : `${baseClass} ${additionalClassOrFn || ""}`.trim();
var getIcon = (icon) => {
if (!icon)
return null;
if (typeof icon === "function") {
return $html2("span", { class: "mr-1" }, icon());
}
if (typeof icon === "object") {
return $html2("span", { class: "mr-1" }, icon);
}
if (typeof icon === "string") {
const parts = icon.trim().split(/\s+/);
const hasRight = parts[parts.length - 1] === "right";
const iconClass = hasRight ? parts.slice(0, -1).join(" ") : icon;
const spacing = hasRight ? "ml-1" : "mr-1";
if (iconClass && !iconClass.startsWith("icon-[") && !iconClass.includes("--")) {
return $html2("span", { class: spacing }, iconClass);
}
return $html2("span", { class: `${iconClass} ${spacing}`.trim() });
}
return null;
};
// src/components/Accordion.js
var Accordion = (props, children) => {
const { class: className, title, name, open, ...rest } = props;
return $html2("div", {
...rest,
class: ui("collapse collapse-arrow bg-base-200 mb-2", className)
}, [
$html2("input", {
type: name ? "radio" : "checkbox",
name,
checked: val(open)
}),
$html2("div", { class: "collapse-title text-xl font-medium" }, title),
$html2("div", { class: "collapse-content" }, children)
]);
};
// src/components/Alert.js
var exports_Alert = {};
__export(exports_Alert, {
Alert: () => Alert
});
var Alert = (props, children) => {
const { class: className, actions, type = "info", soft = true, ...rest } = props;
const iconMap = {
info: "icon-[lucide--info]",
success: "icon-[lucide--check-circle]",
warning: "icon-[lucide--alert-triangle]",
error: "icon-[lucide--alert-circle]"
};
const typeClass = `alert-${type}`;
const softClass = soft ? "alert-soft" : "";
const allClasses = [typeClass, softClass, className].filter(Boolean).join(" ");
const content = children || props.message;
return $html2("div", {
...rest,
role: "alert",
class: ui("alert", allClasses)
}, () => [
getIcon(iconMap[type]),
$html2("div", { class: "flex-1" }, [
$html2("span", {}, [typeof content === "function" ? content() : content])
]),
actions ? $html2("div", { class: "flex-none" }, [
typeof actions === "function" ? actions() : actions
]) : null
].filter(Boolean));
};
// src/components/Autocomplete.js
var exports_Autocomplete = {};
__export(exports_Autocomplete, {
Autocomplete: () => Autocomplete
});
// src/core/i18n.js
var i18n = {
es: {
close: "Cerrar",
confirm: "Confirmar",
cancel: "Cancelar",
search: "Buscar...",
loading: "Cargando...",
nodata: "Sin datos"
},
en: {
close: "Close",
confirm: "Confirm",
cancel: "Cancel",
search: "Search...",
loading: "Loading...",
nodata: "No data"
}
};
var currentLocale = $("es");
var tt = (t) => () => i18n[currentLocale()][t] || t;
// src/components/Input.js
var exports_Input = {};
__export(exports_Input, {
Input: () => Input
});
var Input = (props) => {
const {
class: className,
value,
type = "text",
icon,
oninput,
placeholder,
disabled,
size,
validate,
...rest
} = props;
const isPassword = type === "password";
const visible = $(false);
const errorMsg = $(null);
const iconMap = {
text: "icon-[lucide--text]",
password: "icon-[lucide--lock]",
date: "icon-[lucide--calendar]",
number: "icon-[lucide--hash]",
email: "icon-[lucide--mail]",
search: "icon-[lucide--search]",
tel: "icon-[lucide--phone]",
url: "icon-[lucide--link]"
};
const leftIcon = icon ? getIcon(icon) : iconMap[type] ? getIcon(iconMap[type]) : null;
const getPasswordIcon = () => getIcon(visible() ? "icon-[lucide--eye-off]" : "icon-[lucide--eye]");
const paddingLeft = leftIcon ? "pl-10" : "";
const paddingRight = isPassword ? "pr-10" : "";
const buttonSize = () => {
if (className?.includes("input-xs"))
return "btn-xs";
if (className?.includes("input-sm"))
return "btn-sm";
if (className?.includes("input-lg"))
return "btn-lg";
return "btn-md";
};
const handleInput = (e) => {
const newValue = e.target.value;
if (validate) {
const result = validate(newValue);
errorMsg(result || null);
}
oninput?.(e);
};
const hasError = () => errorMsg() && errorMsg() !== "";
const inputClasses = () => {
let classes = `input w-full ${paddingLeft} ${paddingRight}`;
if (className)
classes += ` ${className}`;
if (hasError())
classes += " input-error";
return classes.trim();
};
const inputElement = $html2("input", {
...rest,
type: () => isPassword ? visible() ? "text" : "password" : type,
placeholder: placeholder || " ",
class: inputClasses,
value,
oninput: handleInput,
disabled: () => val(disabled),
"aria-invalid": () => hasError() ? "true" : "false"
});
return $html2("div", { class: "relative w-full" }, () => [
inputElement,
leftIcon ? $html2("div", {
class: "absolute left-3 inset-y-0 flex items-center pointer-events-none text-base-content/60"
}, leftIcon) : null,
isPassword ? $html2("button", {
type: "button",
class: ui("absolute right-3 inset-y-0 flex items-center", "btn btn-ghost btn-circle opacity-50 hover:opacity-100", buttonSize()),
onclick: (e) => {
e.preventDefault();
visible(!visible());
}
}, () => getPasswordIcon()) : null,
$html2("div", {
class: "text-error text-xs mt-1 px-3 absolute -bottom-5 left-0"
}, () => hasError() ? errorMsg() : null)
]);
};
// src/components/Autocomplete.js
var Autocomplete = (props) => {
const { class: className, items = [], value, onSelect, label, placeholder, ...rest } = props;
const query = $(val(value) || "");
const isOpen = $(false);
const cursor = $(-1);
const list = $(() => {
const q = query().toLowerCase();
const data = val(items) || [];
return q ? data.filter((o) => (typeof o === "string" ? o : o.label).toLowerCase().includes(q)) : data;
});
const pick = (opt) => {
const valStr = typeof opt === "string" ? opt : opt.value;
const labelStr = typeof opt === "string" ? opt : opt.label;
query(labelStr);
if (typeof value === "function")
value(valStr);
onSelect?.(opt);
isOpen(false);
cursor(-1);
};
const nav = (e) => {
const items2 = list();
if (e.key === "ArrowDown") {
e.preventDefault();
isOpen(true);
cursor(Math.min(cursor() + 1, items2.length - 1));
} else if (e.key === "ArrowUp") {
e.preventDefault();
cursor(Math.max(cursor() - 1, 0));
} else if (e.key === "Enter" && cursor() >= 0) {
e.preventDefault();
pick(items2[cursor()]);
} else if (e.key === "Escape") {
isOpen(false);
}
};
return $html2("div", { class: "relative w-full" }, [
Input({
label,
class: className,
placeholder: placeholder || tt("search")(),
value: query,
onfocus: () => isOpen(true),
onblur: () => setTimeout(() => isOpen(false), 150),
onkeydown: nav,
oninput: (e) => {
const v = e.target.value;
query(v);
if (typeof value === "function")
value(v);
isOpen(true);
cursor(-1);
},
...rest
}),
$html2("ul", {
class: "absolute left-0 w-full menu bg-base-100 rounded-box mt-1 p-2 shadow-xl max-h-60 overflow-y-auto border border-base-300 z-50",
style: () => isOpen() && list().length ? "display:block" : "display:none"
}, [
$for(list, (opt, i) => $html2("li", {}, [
$html2("a", {
class: () => `block w-full ${cursor() === i ? "active bg-primary text-primary-content" : ""}`,
onclick: () => pick(opt),
onmouseenter: () => cursor(i)
}, typeof opt === "string" ? opt : opt.label)
]), (opt, i) => (typeof opt === "string" ? opt : opt.value) + i),
() => list().length ? null : $html2("li", { class: "p-2 text-center opacity-50" }, tt("nodata")())
])
]);
};
// src/components/Badge.js
var exports_Badge = {};
__export(exports_Badge, {
Badge: () => Badge
});
var Badge = (props, children) => {
const { class: className, ...rest } = props;
return $html2("span", {
...rest,
class: ui("badge", className)
}, children);
};
// src/components/Button.js
var exports_Button = {};
__export(exports_Button, {
Button: () => Button
});
var Button = (props, children) => {
const { class: className, loading, icon, ...rest } = props;
const iconEl = getIcon(icon);
return $html2("button", {
...rest,
class: ui("btn", className),
disabled: () => val(loading) || val(props.disabled)
}, () => [
val(loading) && $html2("span", { class: "loading loading-spinner" }),
iconEl,
children
].filter(Boolean));
};
// src/components/Checkbox.js
var exports_Checkbox = {};
__export(exports_Checkbox, {
Checkbox: () => Checkbox
});
var Checkbox = (props) => {
const { class: className, value, tooltip, toggle, label, ...rest } = props;
const checkEl = $html2("input", {
...rest,
type: "checkbox",
class: () => ui(val(toggle) ? "toggle" : "checkbox", className),
checked: value
});
const layout = $html2("label", { class: "label cursor-pointer justify-start gap-3" }, [
checkEl,
label ? $html2("span", { class: "label-text" }, label) : null
]);
return tooltip ? $html2("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
};
// src/components/Colorpicker.js
var exports_Colorpicker = {};
__export(exports_Colorpicker, {
Colorpicker: () => Colorpicker
});
var Colorpicker = (props) => {
const { class: className, value, label, ...rest } = props;
const isOpen = $(false);
const palette = [
...["#000", "#1A1A1A", "#333", "#4D4D4D", "#666", "#808080", "#B3B3B3", "#FFF"],
...["#450a0a", "#7f1d1d", "#991b1b", "#b91c1c", "#dc2626", "#ef4444", "#f87171", "#fca5a5"],
...["#431407", "#7c2d12", "#9a3412", "#c2410c", "#ea580c", "#f97316", "#fb923c", "#ffedd5"],
...["#713f12", "#a16207", "#ca8a04", "#eab308", "#facc15", "#fde047", "#fef08a", "#fff9c4"],
...["#064e3b", "#065f46", "#059669", "#10b981", "#34d399", "#4ade80", "#84cc16", "#d9f99d"],
...["#082f49", "#075985", "#0284c7", "#0ea5e9", "#38bdf8", "#7dd3fc", "#22d3ee", "#cffafe"],
...["#1e1b4b", "#312e81", "#4338ca", "#4f46e5", "#6366f1", "#818cf8", "#a5b4fc", "#e0e7ff"],
...["#2e1065", "#4c1d95", "#6d28d9", "#7c3aed", "#8b5cf6", "#a855f7", "#d946ef", "#fae8ff"]
];
const getColor = () => val(value) || "#000000";
return $html2("div", { class: ui("relative w-fit", className) }, [
$html2("button", {
type: "button",
class: "btn px-3 bg-base-100 border-base-300 hover:border-primary/50 flex items-center gap-2 shadow-sm font-normal normal-case",
onclick: (e) => {
e.stopPropagation();
isOpen(!isOpen());
},
...rest
}, [
$html2("div", {
class: "size-5 rounded-sm shadow-inner border border-black/10 shrink-0",
style: () => `background-color: ${getColor()}`
}),
label ? $html2("span", { class: "opacity-80" }, label) : null
]),
$if(isOpen, () => $html2("div", {
class: "absolute left-0 mt-2 p-3 bg-base-100 border border-base-300 shadow-2xl rounded-box z-[110] w-64 select-none",
onclick: (e) => e.stopPropagation()
}, [
$html2("div", { class: "grid grid-cols-8 gap-1" }, palette.map((c) => $html2("button", {
type: "button",
style: `background-color: ${c}`,
class: () => {
const active = getColor().toLowerCase() === c.toLowerCase();
return `size-6 rounded-sm cursor-pointer transition-all hover:scale-125 hover:z-10 active:scale-95 outline-none border border-black/5
${active ? "ring-2 ring-offset-1 ring-primary z-10 scale-110" : ""}`;
},
onclick: () => {
if (typeof value === "function")
value(c);
isOpen(false);
}
})))
])),
$if(isOpen, () => $html2("div", {
class: "fixed inset-0 z-[100]",
onclick: () => isOpen(false)
}))
]);
};
// src/components/Datepicker.js
var exports_Datepicker = {};
__export(exports_Datepicker, {
Datepicker: () => Datepicker
});
var Datepicker = (props) => {
const { class: className, value, range, label, placeholder, hour = false, ...rest } = props;
const isOpen = $(false);
const internalDate = $(new Date);
const hoverDate = $(null);
const startHour = $(0);
const endHour = $(0);
const isRangeMode = () => val(range) === true;
const now = new Date;
const todayStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
const formatDate = (d) => {
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
const selectDate = (date) => {
const dateStr = formatDate(date);
const current = val(value);
if (isRangeMode()) {
if (!current?.start || current.start && current.end) {
if (typeof value === "function") {
value({
start: dateStr,
end: null,
...hour && { startHour: startHour() }
});
}
} else {
const start = current.start;
if (typeof value === "function") {
const newValue = dateStr < start ? { start: dateStr, end: start } : { start, end: dateStr };
if (hour) {
newValue.startHour = current.startHour || startHour();
newValue.endHour = current.endHour || endHour();
}
value(newValue);
}
isOpen(false);
}
} else {
if (typeof value === "function") {
value(hour ? `${dateStr}T${String(startHour()).padStart(2, "0")}:00:00` : dateStr);
}
isOpen(false);
}
};
const displayValue = $(() => {
const v = val(value);
if (!v)
return "";
if (typeof v === "string") {
if (hour && v.includes("T"))
return v.replace("T", " ");
return v;
}
if (v.start && v.end) {
const startStr = hour && v.startHour ? `${v.start} ${String(v.startHour).padStart(2, "0")}:00` : v.start;
const endStr = hour && v.endHour ? `${v.end} ${String(v.endHour).padStart(2, "0")}:00` : v.end;
return `${startStr} - ${endStr}`;
}
if (v.start) {
const startStr = hour && v.startHour ? `${v.start} ${String(v.startHour).padStart(2, "0")}:00` : v.start;
return `${startStr}...`;
}
return "";
});
const move = (m) => {
const d = internalDate();
internalDate(new Date(d.getFullYear(), d.getMonth() + m, 1));
};
const moveYear = (y) => {
const d = internalDate();
internalDate(new Date(d.getFullYear() + y, d.getMonth(), 1));
};
const HourSlider = ({ value: hVal, onChange }) => {
return $html2("div", { class: "flex-1" }, [
$html2("div", { class: "flex gap-2 items-center" }, [
$html2("input", {
type: "range",
min: 0,
max: 23,
value: hVal,
class: "range range-xs flex-1",
oninput: (e) => {
const newHour = parseInt(e.target.value);
onChange(newHour);
}
}),
$html2("span", { class: "text-sm font-mono min-w-[48px] text-center" }, () => String(val(hVal)).padStart(2, "0") + ":00")
])
]);
};
return $html2("div", { class: ui("relative w-full", className) }, [
Input({
label,
placeholder: placeholder || (isRangeMode() ? "Seleccionar rango..." : "Seleccionar fecha..."),
value: displayValue,
readonly: true,
icon: getIcon("icon-[lucide--calendar]"),
onclick: (e) => {
e.stopPropagation();
isOpen(!isOpen());
},
...rest
}),
$if(isOpen, () => $html2("div", {
class: "absolute left-0 mt-2 p-4 bg-base-100 border border-base-300 shadow-2xl rounded-box z-[100] w-80 select-none",
onclick: (e) => e.stopPropagation()
}, [
$html2("div", { class: "flex justify-between items-center mb-4 gap-1" }, [
$html2("div", { class: "flex gap-0.5" }, [
$html2("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(-1) }, getIcon("icon-[lucide--chevrons-left]")),
$html2("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(-1) }, getIcon("icon-[lucide--chevron-left]"))
]),
$html2("span", { class: "font-bold uppercase flex-1 text-center" }, [
() => internalDate().toLocaleString("es-ES", { month: "short", year: "numeric" })
]),
$html2("div", { class: "flex gap-0.5" }, [
$html2("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(1) }, getIcon("icon-[lucide--chevron-right]")),
$html2("button", { type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(1) }, getIcon("icon-[lucide--chevrons-right]"))
])
]),
$html2("div", { class: "grid grid-cols-7 gap-1", onmouseleave: () => hoverDate(null) }, [
...["L", "M", "X", "J", "V", "S", "D"].map((d) => $html2("div", { class: "text-[10px] opacity-40 font-bold text-center" }, d)),
() => {
const d = internalDate();
const year = d.getFullYear();
const month = d.getMonth();
const firstDay = new Date(year, month, 1).getDay();
const offset = firstDay === 0 ? 6 : firstDay - 1;
const daysInMonth = new Date(year, month + 1, 0).getDate();
const nodes = [];
for (let i = 0;i < offset; i++)
nodes.push($html2("div"));
for (let i = 1;i <= daysInMonth; i++) {
const date = new Date(year, month, i);
const dStr = formatDate(date);
nodes.push($html2("button", {
type: "button",
class: () => {
const v = val(value);
const h = hoverDate();
const isStart = typeof v === "string" ? v.split("T")[0] === dStr : v?.start === dStr;
const isEnd = v?.end === dStr;
let inRange = false;
if (isRangeMode() && v?.start) {
const start = v.start;
if (!v.end && h) {
inRange = dStr > start && dStr <= h || dStr < start && dStr >= h;
} else if (v.end) {
inRange = dStr > start && dStr < v.end;
}
}
const base = "btn btn-xs p-0 aspect-square min-h-0 h-auto font-normal relative";
const state = isStart || isEnd ? "btn-primary z-10" : inRange ? "bg-primary/20 border-none rounded-none" : "btn-ghost";
const today = dStr === todayStr ? "ring-1 ring-primary ring-inset font-black text-primary" : "";
return `${base} ${state} ${today}`;
},
onmouseenter: () => {
if (isRangeMode())
hoverDate(dStr);
},
onclick: () => selectDate(date)
}, [i.toString()]));
}
return nodes;
}
]),
hour ? $html2("div", { class: "mt-3 pt-2 border-t border-base-300" }, [
isRangeMode() ? $html2("div", { class: "flex gap-4" }, [
HourSlider({
value: startHour,
onChange: (newHour) => {
startHour(newHour);
const currentVal = val(value);
if (currentVal?.start)
value({ ...currentVal, startHour: newHour });
}
}),
HourSlider({
value: endHour,
onChange: (newHour) => {
endHour(newHour);
const currentVal = val(value);
if (currentVal?.end)
value({ ...currentVal, endHour: newHour });
}
})
]) : HourSlider({
value: startHour,
onChange: (newHour) => {
startHour(newHour);
const currentVal = val(value);
if (currentVal && typeof currentVal === "string" && currentVal.includes("-")) {
value(currentVal.split("T")[0] + "T" + String(newHour).padStart(2, "0") + ":00:00");
}
}
})
]) : null
])),
$if(isOpen, () => $html2("div", { class: "fixed inset-0 z-[90]", onclick: () => isOpen(false) }))
]);
};
// src/components/Drawer.js
var exports_Drawer = {};
__export(exports_Drawer, {
Drawer: () => Drawer
});
var Drawer = (props, children) => {
const { class: className, id, open, side, content, ...rest } = props;
const drawerId = id || `drawer-${Math.random().toString(36).slice(2, 9)}`;
return $html2("div", {
...rest,
class: ui("drawer", className)
}, [
$html2("input", {
id: drawerId,
type: "checkbox",
class: "drawer-toggle",
checked: () => typeof open === "function" ? open() : open,
onchange: (e) => {
if (typeof open === "function")
open(e.target.checked);
}
}),
$html2("div", { class: "drawer-content" }, [
typeof content === "function" ? content() : content
]),
$html2("div", { class: "drawer-side" }, [
$html2("label", {
for: drawerId,
class: "drawer-overlay",
onclick: () => {
if (typeof open === "function")
open(false);
}
}),
$html2("div", { class: "min-h-full bg-base-200 w-80" }, [
typeof side === "function" ? side() : side
])
])
]);
};
// src/components/Dropdown.js
var exports_Dropdown = {};
__export(exports_Dropdown, {
Dropdown: () => Dropdown
});
var currentOpen = null;
if (typeof window !== "undefined" && !window.__dropdownHandlerRegistered) {
window.addEventListener("click", (e) => {
if (currentOpen && !currentOpen.contains(e.target)) {
currentOpen.open = false;
currentOpen = null;
}
});
window.__dropdownHandlerRegistered = true;
}
var Dropdown = (props) => {
const { class: className, label, icon, items, ...rest } = props;
return $html("details", {
...rest,
class: ui("dropdown", className)
}, [
$html("summary", {
class: "btn m-1 flex items-center gap-2 list-none cursor-pointer",
style: "display: inline-flex;",
onclick: (e) => {
const details = e.currentTarget.closest("details");
if (currentOpen && currentOpen !== details) {
currentOpen.open = false;
}
setTimeout(() => {
currentOpen = details.open ? details : null;
}, 0);
}
}, [
() => icon ? typeof icon === "function" ? icon() : icon : null,
() => label ? typeof label === "function" ? label() : label : null
]),
$html("ul", {
tabindex: "-1",
class: "dropdown-content z-[50] menu p-2 shadow bg-base-100 rounded-box w-52 border border-base-300"
}, [
() => {
const currentItems = typeof items === "function" ? items() : items || [];
return currentItems.map((item) => $html("li", {}, [
$html("a", {
class: item.class || "",
onclick: (e) => {
if (item.onclick)
item.onclick(e);
const details = e.currentTarget.closest("details");
if (details) {
details.open = false;
if (currentOpen === details)
currentOpen = null;
}
}
}, [
item.icon ? $html("span", {}, item.icon) : null,
$html("span", {}, item.label)
])
]));
}
])
]);
};
// src/components/Fab.js
var exports_Fab = {};
__export(exports_Fab, {
Fab: () => Fab
});
var Fab = (props) => {
const { class: className, icon, label, actions = [], position = "bottom-6 right-6", ...rest } = props;
return $html2("div", {
...rest,
class: ui(`fab absolute ${position} flex flex-col-reverse items-end gap-3 z-[100]`, className)
}, [
$html2("div", {
tabindex: 0,
role: "button",
class: "btn btn-lg btn-circle btn-primary shadow-2xl"
}, [
icon ? getIcon(icon) : null,
!icon && label ? label : null
]),
...val(actions).map((act) => $html2("div", { class: "flex items-center gap-3 transition-all duration-300" }, [
act.label ? $html2("span", { class: "badge badge-ghost shadow-sm whitespace-nowrap" }, act.label) : null,
$html2("button", {
type: "button",
class: `btn btn-circle shadow-lg ${act.class || ""}`,
onclick: (e) => {
e.stopPropagation();
act.onclick?.(e);
}
}, [act.icon ? getIcon(act.icon) : act.text || ""])
]))
]);
};
// src/components/Fieldset.js
var exports_Fieldset = {};
__export(exports_Fieldset, {
Fieldset: () => Fieldset
});
var Fieldset = (props, children) => {
const { class: className, legend, ...rest } = props;
return $html2("fieldset", {
...rest,
class: ui("fieldset bg-base-200 border border-base-300 p-4 rounded-lg", className)
}, [
() => {
const legendText = val(legend);
return legendText ? $html2("legend", { class: "fieldset-legend font-bold" }, [legendText]) : null;
},
children
]);
};
// src/components/Fileinput.js
var exports_Fileinput = {};
__export(exports_Fileinput, {
Fileinput: () => Fileinput
});
var Fileinput = (props) => {
const { class: className, tooltip, max = 2, accept = "*", onSelect, ...rest } = props;
const selectedFiles = $([]);
const isDragging = $(false);
const error = $(null);
const MAX_BYTES = max * 1024 * 1024;
const handleFiles = (files) => {
const fileList = Array.from(files);
error(null);
const oversized = fileList.find((f) => f.size > MAX_BYTES);
if (oversized) {
error(`Máx ${max}MB`);
return;
}
selectedFiles([...selectedFiles(), ...fileList]);
onSelect?.(selectedFiles());
};
const removeFile = (index) => {
const updated = selectedFiles().filter((_, i) => i !== index);
selectedFiles(updated);
onSelect?.(updated);
};
return $html2("fieldset", { ...rest, class: ui("fieldset w-full p-0", className) }, [
$html2("div", {
class: () => `w-full ${tooltip ? "tooltip tooltip-top before:z-50 after:z-50" : ""}`,
"data-tip": tooltip
}, [
$html2("label", {
class: () => `
relative flex items-center justify-between w-full h-12 px-4
border-2 border-dashed rounded-lg cursor-pointer
transition-all duration-200
${isDragging() ? "border-primary bg-primary/10" : "border-base-content/20 bg-base-100 hover:bg-base-200"}
`,
ondragover: (e) => {
e.preventDefault();
isDragging(true);
},
ondragleave: () => isDragging(false),
ondrop: (e) => {
e.preventDefault();
isDragging(false);
handleFiles(e.dataTransfer.files);
}
}, [
$html2("div", { class: "flex items-center gap-3 w-full" }, [
getIcon("icon-[lucide--upload]"),
$html2("span", { class: "text-sm opacity-70 truncate grow text-left" }, "Arrastra o selecciona archivos..."),
$html2("span", { class: "text-[10px] opacity-40 shrink-0" }, `Máx ${max}MB`)
]),
$html2("input", {
type: "file",
multiple: true,
accept,
class: "hidden",
onchange: (e) => handleFiles(e.target.files)
})
])
]),
() => error() ? $html2("span", { class: "text-[10px] text-error mt-1 px-1 font-medium" }, error()) : null,
$if(() => selectedFiles().length > 0, () => $html2("ul", { class: "mt-2 space-y-1" }, [
$for(selectedFiles, (file, index) => $html2("li", { class: "flex items-center justify-between p-1.5 pl-3 text-xs bg-base-200/50 rounded-md border border-base-300" }, [
$html2("div", { class: "flex items-center gap-2 truncate" }, [
$html2("span", { class: "opacity-50" }, "\uD83D\uDCC4"),
$html2("span", { class: "truncate font-medium max-w-[200px]" }, file.name),
$html2("span", { class: "text-[9px] opacity-40" }, `(${(file.size / 1024).toFixed(0)} KB)`)
]),
$html2("button", {
type: "button",
class: "btn btn-ghost btn-xs btn-circle",
onclick: (e) => {
e.preventDefault();
e.stopPropagation();
removeFile(index);
}
}, [getIcon("icon-[lucide--x]")])
]), (file) => file.name + file.lastModified)
]))
]);
};
// src/components/Indicator.js
var exports_Indicator = {};
__export(exports_Indicator, {
Indicator: () => Indicator
});
var Indicator = (props, children) => {
const { value, class: className, ...rest } = props;
return $html2("div", {
...rest,
class: "indicator"
}, () => [
value ? $html2("span", {
class: ui("indicator-item badge", className)
}, () => typeof value === "function" ? value() : value) : null,
children
].filter(Boolean));
};
// src/components/Label.js
var exports_Label = {};
__export(exports_Label, {
Label: () => Label
});
var Label = (props) => {
const { children, value, floating = false, error, required, class: className, ...rest } = props;
if (floating) {
return $html2("label", { class: ui("floating-label w-full", className), ...rest }, () => [
value ? $html2("span", {}, value) : null,
children,
error ? $html2("span", { class: "text-error text-xs" }, val(error)) : null
]);
}
return $html2("label", { class: ui("input w-full", className), ...rest }, () => [
value ? $html2("span", { class: "label" }, value) : null,
children,
error ? $html2("span", { class: "text-error text-xs" }, val(error)) : null
]);
};
// src/components/List.js
var exports_List = {};
__export(exports_List, {
List: () => List
});
var List = (props) => {
const { class: className, items, header, render, keyFn = (item, index) => item.id ?? index, ...rest } = props;
const listItems = $for(items, (item, index) => $html2("li", { class: "list-row" }, [render(item, index)]), keyFn);
return $html2("ul", {
...rest,
class: ui("list bg-base-100 rounded-box shadow-md", className)
}, header ? [$if(header, () => $html2("li", { class: "p-4 pb-2 text-xs opacity-60" }, [val(header)])), listItems] : listItems);
};
// src/components/Menu.js
var exports_Menu = {};
__export(exports_Menu, {
Menu: () => Menu
});
var Menu = (props) => {
const { class: className, items, ...rest } = props;
const renderItems = (items2) => $for(() => items2 || [], (it) => $html2("li", {}, [
it.children ? $html2("details", { open: it.open }, [
$html2("summary", {}, [it.icon && $html2("span", { class: "mr-2" }, it.icon), it.label]),
$html2("ul", {}, renderItems(it.children))
]) : $html2("a", { class: () => val(it.active) ? "active" : "", onclick: it.onclick }, [
it.icon && $html2("span", { class: "mr-2" }, it.icon),
it.label
])
]), (it, i) => it.label || i);
return $html2("ul", { ...rest, class: ui("menu bg-base-200 rounded-box", className) }, renderItems(items));
};
// src/components/Modal.js
var exports_Modal = {};
__export(exports_Modal, {
Modal: () => Modal
});
var Modal = (props, children) => {
const { class: className, title, buttons, open, ...rest } = props;
let dialogElement = null;
const handleOpen = () => {
const isOpen = typeof open === "function" ? open() : open;
if (!dialogElement)
return;
if (isOpen) {
if (!dialogElement.open)
dialogElement.showModal();
} else {
if (dialogElement.open)
dialogElement.close();
}
};
$watch2(() => handleOpen());
const close = () => {
if (typeof open === "function")
open(false);
};
return $html2("dialog", {
...rest,
ref: (el) => {
dialogElement = el;
if (el)
handleOpen();
},
class: ui("modal", className),
onclose: close,
oncancel: close
}, [
$html2("div", { class: "modal-box" }, [
title ? $html2("h3", { class: "text-lg font-bold mb-4" }, () => typeof title === "function" ? title() : title) : null,
$html2("div", { class: "py-2" }, [
typeof children === "function" ? children() : children
]),
$html2("div", { class: "modal-action" }, [
$html2("form", { method: "dialog", class: "flex gap-2" }, [
...(Array.isArray(buttons) ? buttons : [buttons]).filter(Boolean),
Button({ type: "submit" }, tt("close")())
])
])
]),
$html2("form", { method: "dialog", class: "modal-backdrop" }, [
$html2("button", {}, "close")
])
]);
};
// src/components/Navbar.js
var exports_Navbar = {};
__export(exports_Navbar, {
Navbar: () => Navbar
});
var Navbar = (props, children) => {
const { class: className, ...rest } = props;
return $html2("div", { ...rest, class: ui("navbar bg-base-100 shadow-sm px-4", className) }, children);
};
// src/components/Radio.js
var exports_Radio = {};
__export(exports_Radio, {
Radio: () => Radio
});
var Radio = (props) => {
const { class: className, label, tooltip, value, inputValue, name, ...rest } = props;
const radioEl = $html2("input", {
...rest,
type: "radio",
name,
class: ui("radio", className),
checked: () => val(value) === inputValue,
onclick: () => {
if (typeof value === "function")
value(inputValue);
}
});
if (!label && !tooltip)
return radioEl;
const layout = $html2("label", { class: "label cursor-pointer justify-start gap-3" }, [
radioEl,
label ? $html2("span", { class: "label-text" }, label) : null
]);
return tooltip ? $html2("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
};
// src/components/Range.js
var exports_Range = {};
__export(exports_Range, {
Range: () => Range
});
var Range = (props) => {
const { class: className, label, tooltip, value, ...rest } = props;
const rangeEl = $html2("input", {
...rest,
type: "range",
class: ui("range", className),
value,
disabled: () => val(props.disabled)
});
if (!label && !tooltip)
return rangeEl;
const layout = $html2("div", { class: "flex flex-col gap-2" }, [
label ? $html2("span", { class: "label-text" }, label) : null,
rangeEl
]);
return tooltip ? $html2("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
};
// src/components/Rating.js
var exports_Rating = {};
__export(exports_Rating, {
Rating: () => Rating
});
var Rating = (props) => {
const { class: className, value, count = 5, mask = "mask-star", readonly = false, onchange, ...rest } = props;
const ratingGroup = `rating-${Math.random().toString(36).slice(2, 7)}`;
return $html2("div", {
...rest,
class: () => ui(`rating ${val(readonly) ? "pointer-events-none" : ""}`, className)
}, Array.from({ length: val(count) }, (_, i) => {
const starValue = i + 1;
return $html2("input", {
type: "radio",
name: ratingGroup,
class: `mask ${mask}`,
checked: () => Math.round(val(value)) === starValue,
onchange: () => {
if (!val(readonly)) {
if (typeof onchange === "function") {
onchange(starValue);
} else if (typeof value === "function") {
value(starValue);
}
}
}
});
}));
};
// src/components/Select.js
var exports_Select = {};
__export(exports_Select, {
Select: () => Select
});
var Select = (props) => {
const { class: className, label, items, value, ...rest } = props;
const selectEl = $html2("select", {
...rest,
class: ui("select select-bordered w-full", className),
value
}, $for(() => val(items) || [], (opt) => $html2("option", {
value: opt.value,
$selected: () => String(val(value)) === String(opt.value)
}, opt.label), (opt) => opt.value));
if (!label)
return selectEl;
return $html2("label", { class: "fieldset-label flex flex-col gap-1" }, [
$html2("span", {}, label),
selectEl
]);
};
// src/components/Stack.js
var exports_Stack = {};
__export(exports_Stack, {
Stack: () => Stack
});
var Stack = (props, children) => {
const { class: className, ...rest } = props;
return $html2("div", { ...rest, class: ui("stack", className) }, children);
};
// src/components/Stat.js
var exports_Stat = {};
__export(exports_Stat, {
Stat: () => Stat
});
var Stat = (props) => {
const { class: className, icon, label, value, desc, ...rest } = props;
return $html2("div", { ...rest, class: ui("stat", className) }, [
icon && $html2("div", { class: "stat-figure text-secondary" }, icon),
label && $html2("div", { class: "stat-title" }, label),
$html2("div", { class: "stat-value" }, () => val(value) ?? value),
desc && $html2("div", { class: "stat-desc" }, desc)
]);
};
// src/components/Swap.js
var exports_Swap = {};
__export(exports_Swap, {
Swap: () => Swap
});
var Swap = (props) => {
const { class: className, value, on, off, ...rest } = props;
return $html2("label", { ...rest, class: ui("swap", className) }, [
$html2("input", {
type: "checkbox",
checked: () => val(value),
onclick: (e) => {
if (typeof value === "function") {
value(e.target.checked);
}
}
}),
$html2("div", { class: "swap-on" }, on),
$html2("div", { class: "swap-off" }, off)
]);
};
// src/components/Table.js
var exports_Table = {};
__export(exports_Table, {
Table: () => Table
});
var Table = (props) => {
const { class: className, items = [], columns = [], keyFn, zebra = false, pinRows = false, empty = tt("nodata")(), ...rest } = props;
const tableClass = () => {
const zebraClass = val(zebra) ? "table-zebra" : "";
const pinRowsClass = val(pinRows) ? "table-pin-rows" : "";
return ui("table", className, zebraClass, pinRowsClass);
};
const getInternalKeyFn = keyFn || ((item, idx) => item.id || idx);
return $html2("div", { class: "overflow-x-auto w-full bg-base-100 rounded-box border border-base-300" }, [
$html2("table", { ...rest, class: tableClass }, [
$html2("thead", {}, [
$html2("tr", {}, columns.map((col) => $html2("th", { class: col.class || "" }, col.label)))
]),
$html2("tbody", {}, [
$for(items, (item, index) => {
const it = () => {
const currentItems = val(items);
const key = getInternalKeyFn(item, index);
return currentItems.find((u, i) => getInternalKeyFn(u, i) === key) || item;
};
return $html2("tr", { class: "hover" }, columns.map((col) => {
const cellContent = () => {
const latestItem = it();
if (col.render)
return col.render(latestItem, index);
return val(latestItem[col.key]);
};
return $html2("td", { class: col.class || "" }, [cellContent]);
}));
}, getInternalKeyFn),
$if(() => val(items).length === 0, () => $html2("tr", {}, [
$html2("td", { colspan: columns.length, class: "text-center p-10 opacity-50" }, [
val(empty)
])
]))
])
])
]);
};
// src/components/Tabs.js
var exports_Tabs = {};
__export(exports_Tabs, {
Tabs: () => Tabs
});
var Tabs = (props) => {
const { items, class: className, ...rest } = props;
const itemsSignal = typeof items === "function" ? items : () => items || [];
const activeIndex = $(0);
$watch(() => {
const idx = itemsSignal().findIndex((it) => val(it.active) === true);
if (idx !== -1 && idx !== activeIndex())
activeIndex(idx);
});
return $html2("div", { ...rest, class: "w-full" }, [
$html2("div", {
role: "tablist",
class: ui("tabs", className || "tabs-box")
}, () => {
const list = itemsSignal();
return list.map((it, idx) => {
const isSelected = () => activeIndex() === idx;
const tab = $html2("button", {
role: "tab",
class: () => ui("tab", isSelected() ? "tab-active" : ""),
onclick: (e) => {
e.preventDefault();
if (!val(it.disabled)) {
if (it.onclick)
it.onclick();
activeIndex(idx);
}
}
});
$watch(() => {
const content = val(it.label);
if (content instanceof Node) {
tab.replaceChildren(content);
} else {
tab.textContent = String(content);
}
});
return tab;
});
}),
$html2("div", { class: "tab-panels" }, () => {
return itemsSignal().map((it, idx) => {
const isVisible = () => activeIndex() === idx;
return $html2("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
]);
});
})
]);
};
// src/components/Timeline.js
var exports_Timeline = {};
__export(exports_Timeline, {
Timeline: () => Timeline
});
var Timeline = (props) => {
const { class: className, items = [], vertical = true, compact = false, ...rest } = props;
const iconMap = {
info: "icon-[lucide--info]",
success: "icon-[lucide--check-circle]",
warning: "icon-[lucide--alert-triangle]",
error: "icon-[lucide--alert-circle]"
};
return $html2("ul", {
...rest,
class: () => ui(`timeline ${val(vertical) ? "timeline-vertical" : "timeline-horizontal"} ${val(compact) ? "timeline-compact" : ""}`, className)
}, () => {
const list = (typeof items === "function" ? items() : items) || [];
return list.map((item, i) => {
const isFirst = i === 0;
const isLast = i === list.length - 1;
const itemType = item.type || "success";
const isCompleted = () => val(item.completed);
const prevCompleted = () => i > 0 && val(list[i - 1].completed);
const renderSlot = (content) => typeof content === "function" ? content() : content;
return $html2("li", { class: "flex-1" }, [
!isFirst ? $html2("hr", { class: () => prevCompleted() ? "bg-primary" : "" }) : null,
$html2("div", { class: "timeline-start" }, [() => renderSlot(item.title)]),
$html2("div", { class: "timeline-middle" }, [
() => item.icon ? getIcon(item.icon) : getIcon(iconMap[itemType] || iconMap.success)
]),
$html2("div", { class: "timeline-end timeline-box shadow-sm" }, [() => renderSlot(item.detail)]),
!isLast ? $html2("hr", { class: () => isCompleted() ? "bg-primary" : "" }) : null
]);
});
});
};
// src/components/Toast.js
var exports_Toast = {};
__export(exports_Toast, {
Toast: () => Toast
});
var Toast = (message, type = "alert-success", duration = 3500) => {
let container = document.getElementById("sigpro-toast-container");
if (!container) {
container = $html2("div", {
id: "sigpro-toast-container",
class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col gap-2 pointer-events-none"
});
document.body.appendChild(container);
}
const toastHost = $html2("div", { style: "display: contents" });
container.appendChild(toastHost);
let timeoutId;
const close = () => {
clearTimeout(timeoutId);
const el = toastHost.firstElementChild;
if (el && !el.classList.contains("opacity-0")) {
el.classList.add("translate-x-full", "opacity-0");
setTimeout(() => {
instance.destroy();
toastHost.remove();
if (!container.hasChildNodes())
container.remove();
}, 300);
} else {
instance.destroy();
toastHost.remove();
}
};
const ToastComponent = () => {
const closeIcon = getIcon("icon-[lucide--x]");
const el = $html2("div", {
class: `alert alert-soft ${type} shadow-lg transition-all duration-300 translate-x-10 opacity-0 pointer-events-auto`
}, [
$html2("span", {}, [typeof message === "function" ? message() : message]),
Button({
class: "btn-xs btn-circle btn-ghost",
onclick: close
}, closeIcon)
]);
requestAnimationFrame(() => el.classList.remove("translate-x-10", "opacity-0"));
return el;
};
const instance = $mount(ToastComponent, toastHost);
if (duration > 0) {
timeoutId = setTimeout(close, duration);
}
return close;
};
// src/components/Tooltip.js
var exports_Tooltip = {};
__export(exports_Tooltip, {
Tooltip: () => Tooltip
});
var Tooltip = (props, children) => $html2("div", {
...props,
class: () => ui("tooltip", props.class),
"data-tip": props.tip
}, children);
// src/components/index.js
var Components = {
...exports_Accordion,
...exports_Alert,
...exports_Autocomplete,
...exports_Badge,
...exports_Button,
...exports_Checkbox,
...exports_Colorpicker,
...exports_Datepicker,
...exports_Drawer,
...exports_Dropdown,
...exports_Fab,
...exports_Fieldset,
...exports_Fileinput,
...exports_Indicator,
...exports_Input,
...exports_Label,
...exports_List,
...exports_Menu,
...exports_Modal,
...exports_Navbar,
...exports_Radio,
...exports_Range,
...exports_Rating,
...exports_Select,
...exports_Stack,
...exports_Stat,
...exports_Swap,
...exports_Table,
...exports_Tabs,
...exports_Timeline,
...exports_Toast,
...exports_Tooltip
};
var components_default = {
...Components,
install: (target = window) => {
Object.entries(Components).forEach(([name, component]) => {
target[name] = component;
});
console.log("\uD83D\uDE80 SigproUI");
}
};
// index.js
if (typeof window !== "undefined") {
Object.entries(exports_components).forEach(([name, component]) => {
window[name] = component;
});
window.Utils = exports_utils;
window.tt = tt;
window.SigProUI = { ...exports_components, Utils: exports_utils, tt };
console.log("\uD83C\uDFA8 SigProUI ready");
}
export {
val,
ui,
tt,
getIcon,
Tooltip,
Toast,
Timeline,
Tabs,
Table,
Swap,
Stat,
Stack,
Select,
Rating,
Range,
Radio,
Navbar,
Modal,
Menu,
List,
Label,
Input,
Indicator,
Fileinput,
Fieldset,
Fab,
Dropdown,
Drawer,
Datepicker,
Colorpicker,
Checkbox,
Button,
Badge,
Autocomplete,
Alert,
Accordion
};