new functions $
This commit is contained in:
321
UI/sigpro-ui.js
321
UI/sigpro-ui.js
@@ -2,7 +2,8 @@
|
|||||||
* SigPro UI - daisyUI v5 & Tailwind v4 Plugin
|
* SigPro UI - daisyUI v5 & Tailwind v4 Plugin
|
||||||
* Provides a set of reactive functional components, flow control and i18n.
|
* Provides a set of reactive functional components, flow control and i18n.
|
||||||
*/
|
*/
|
||||||
export const UI = ($, defaultLang = "es") => {
|
export const UI = (core, defaultLang = "es") => {
|
||||||
|
const { $, $if, $for, $watch, $html, $mount } = core;
|
||||||
const ui = {};
|
const ui = {};
|
||||||
|
|
||||||
// --- I18N CORE ---
|
// --- I18N CORE ---
|
||||||
@@ -115,15 +116,15 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
/** RESPONSE */
|
/** RESPONSE */
|
||||||
ui.Response = (reqObj, renderFn) =>
|
ui.Response = (reqObj, renderFn) =>
|
||||||
$.html("div", { class: "res-container" }, [
|
$html("div", { class: "res-container" }, [
|
||||||
$.if(reqObj.loading, $.html("div", { class: "flex justify-center p-4" }, $.html("span", { class: "loading loading-dots text-primary" }))),
|
$if(reqObj.loading, $html("div", { class: "flex justify-center p-4" }, $html("span", { class: "loading loading-dots text-primary" }))),
|
||||||
$.if(reqObj.error, () =>
|
$if(reqObj.error, () =>
|
||||||
$.html("div", { role: "alert", class: "alert alert-error" }, [
|
$html("div", { role: "alert", class: "alert alert-error" }, [
|
||||||
$.html("span", {}, reqObj.error()),
|
$html("span", {}, reqObj.error()),
|
||||||
ui.Button({ class: "btn-xs btn-ghost border-current", onclick: () => reqObj.reload() }, "Retry"),
|
ui.Button({ class: "btn-xs btn-ghost border-current", onclick: () => reqObj.reload() }, "Retry"),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
$.if(reqObj.success, () => {
|
$if(reqObj.success, () => {
|
||||||
const current = reqObj.data();
|
const current = reqObj.data();
|
||||||
return current !== null ? renderFn(current) : null;
|
return current !== null ? renderFn(current) : null;
|
||||||
}),
|
}),
|
||||||
@@ -134,7 +135,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
/** BUTTON */
|
/** BUTTON */
|
||||||
ui.Button = (props, children) => {
|
ui.Button = (props, children) => {
|
||||||
const { badge, badgeClass, tooltip, icon, loading, ...rest } = props;
|
const { badge, badgeClass, tooltip, icon, loading, ...rest } = props;
|
||||||
const btn = $.html(
|
const btn = $html(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
@@ -142,19 +143,19 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
disabled: () => val(loading) || val(props.disabled) || val(props.disabled),
|
disabled: () => val(loading) || val(props.disabled) || val(props.disabled),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
() => (val(loading) ? $.html("span", { class: "loading loading-spinner" }) : null),
|
() => (val(loading) ? $html("span", { class: "loading loading-spinner" }) : null),
|
||||||
icon ? $.html("span", { class: "mr-1" }, icon) : null,
|
icon ? $html("span", { class: "mr-1" }, icon) : null,
|
||||||
children,
|
children,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
let out = btn;
|
let out = btn;
|
||||||
if (badge) {
|
if (badge) {
|
||||||
out = $.html("div", { class: "indicator" }, [
|
out = $html("div", { class: "indicator" }, [
|
||||||
$.html("span", { class: joinClass("indicator-item badge", badgeClass || "badge-secondary") }, badge),
|
$html("span", { class: joinClass("indicator-item badge", badgeClass || "badge-secondary") }, badge),
|
||||||
out,
|
out,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
return tooltip ? $.html("div", { class: "tooltip", "data-tip": tooltip }, out) : out;
|
return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, out) : out;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** INPUT */
|
/** INPUT */
|
||||||
@@ -171,7 +172,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
email: iconMail,
|
email: iconMail,
|
||||||
};
|
};
|
||||||
|
|
||||||
const inputEl = $.html("input", {
|
const inputEl = $html("input", {
|
||||||
...rest,
|
...rest,
|
||||||
type: () => (isPassword ? (visible() ? "text" : "password") : type),
|
type: () => (isPassword ? (visible() ? "text" : "password") : type),
|
||||||
placeholder: props.placeholder || label || (isSearch ? tt("search")() : " "),
|
placeholder: props.placeholder || label || (isSearch ? tt("search")() : " "),
|
||||||
@@ -181,19 +182,19 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
disabled: () => val(props.disabled),
|
disabled: () => val(props.disabled),
|
||||||
});
|
});
|
||||||
|
|
||||||
const leftIcon = icon ? icon : iconsByType[type] ? $.html("img", { src: iconsByType[type], class: "w-5 h-5 opacity-50", alt: type }) : null;
|
const leftIcon = icon ? icon : iconsByType[type] ? $html("img", { src: iconsByType[type], class: "w-5 h-5 opacity-50", alt: type }) : null;
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"label",
|
"label",
|
||||||
{
|
{
|
||||||
class: () => joinClass("input input-bordered floating-label flex items-center gap-2 w-full relative", val(error) ? "input-error" : ""),
|
class: () => joinClass("input input-bordered floating-label flex items-center gap-2 w-full relative", val(error) ? "input-error" : ""),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
leftIcon ? $.html("div", { class: "order-1 shrink-0" }, leftIcon) : null,
|
leftIcon ? $html("div", { class: "order-1 shrink-0" }, leftIcon) : null,
|
||||||
label ? $.html("span", { class: "text-base-content/60 order-0" }, label) : null,
|
label ? $html("span", { class: "text-base-content/60 order-0" }, label) : null,
|
||||||
inputEl,
|
inputEl,
|
||||||
isPassword
|
isPassword
|
||||||
? $.html(
|
? $html(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
type: "button",
|
type: "button",
|
||||||
@@ -204,20 +205,20 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
() =>
|
() =>
|
||||||
$.html("img", {
|
$html("img", {
|
||||||
class: "w-5 h-5",
|
class: "w-5 h-5",
|
||||||
src: visible() ? iconShow : iconHide,
|
src: visible() ? iconShow : iconHide,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
tip
|
tip
|
||||||
? $.html(
|
? $html(
|
||||||
"div",
|
"div",
|
||||||
{ class: "tooltip tooltip-left order-4", "data-tip": tip },
|
{ class: "tooltip tooltip-left order-4", "data-tip": tip },
|
||||||
$.html("span", { class: "badge badge-ghost badge-xs cursor-help" }, "?"),
|
$html("span", { class: "badge badge-ghost badge-xs cursor-help" }, "?"),
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
() => (val(error) ? $.html("span", { class: "text-error text-[10px] absolute -bottom-5 left-2" }, val(error)) : null),
|
() => (val(error) ? $html("span", { class: "text-error text-[10px] absolute -bottom-5 left-2" }, val(error)) : null),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -226,17 +227,17 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
ui.Select = (props) => {
|
ui.Select = (props) => {
|
||||||
const { label, options, value, ...rest } = props;
|
const { label, options, value, ...rest } = props;
|
||||||
|
|
||||||
const selectEl = $.html(
|
const selectEl = $html(
|
||||||
"select",
|
"select",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
class: joinClass("select select-bordered w-full", props.class || props.class),
|
class: joinClass("select select-bordered w-full", props.class || props.class),
|
||||||
value: value
|
value: value
|
||||||
},
|
},
|
||||||
$.for(
|
$for(
|
||||||
() => val(options) || [],
|
() => val(options) || [],
|
||||||
(opt) =>
|
(opt) =>
|
||||||
$.html(
|
$html(
|
||||||
"option",
|
"option",
|
||||||
{
|
{
|
||||||
value: opt.value,
|
value: opt.value,
|
||||||
@@ -250,7 +251,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
if (!label) return selectEl;
|
if (!label) return selectEl;
|
||||||
|
|
||||||
return $.html("label", { class: "fieldset-label flex flex-col gap-1" }, [$.html("span", {}, label), selectEl]);
|
return $html("label", { class: "fieldset-label flex flex-col gap-1" }, [$html("span", {}, label), selectEl]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** AUTOCOMPLETE */
|
/** AUTOCOMPLETE */
|
||||||
@@ -296,7 +297,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return $.html("div", { class: "relative w-full" }, [
|
return $html("div", { class: "relative w-full" }, [
|
||||||
ui.Input({
|
ui.Input({
|
||||||
label,
|
label,
|
||||||
placeholder: placeholder || tt("search")(),
|
placeholder: placeholder || tt("search")(),
|
||||||
@@ -313,18 +314,18 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
},
|
},
|
||||||
...rest,
|
...rest,
|
||||||
}),
|
}),
|
||||||
$.html(
|
$html(
|
||||||
"ul",
|
"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",
|
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"),
|
style: () => (isOpen() && list().length ? "display:block" : "display:none"),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.for(
|
$for(
|
||||||
list,
|
list,
|
||||||
(opt, i) =>
|
(opt, i) =>
|
||||||
$.html("li", {}, [
|
$html("li", {}, [
|
||||||
$.html(
|
$html(
|
||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
class: () => `block w-full ${cursor() === i ? "active bg-primary text-primary-content" : ""}`,
|
class: () => `block w-full ${cursor() === i ? "active bg-primary text-primary-content" : ""}`,
|
||||||
@@ -336,7 +337,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
]),
|
]),
|
||||||
(opt, i) => (typeof opt === "string" ? opt : opt.value) + i,
|
(opt, i) => (typeof opt === "string" ? opt : opt.value) + i,
|
||||||
),
|
),
|
||||||
() => (list().length ? null : $.html("li", { class: "p-2 text-center opacity-50" }, "No results")),
|
() => (list().length ? null : $html("li", { class: "p-2 text-center opacity-50" }, "No results")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
@@ -400,13 +401,13 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
internalDate(new Date(d.getFullYear() + y, d.getMonth(), 1));
|
internalDate(new Date(d.getFullYear() + y, d.getMonth(), 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
return $.html("div", { class: "relative w-full" }, [
|
return $html("div", { class: "relative w-full" }, [
|
||||||
ui.Input({
|
ui.Input({
|
||||||
label,
|
label,
|
||||||
placeholder: placeholder || (isRangeMode() ? "Seleccionar rango..." : "Seleccionar fecha..."),
|
placeholder: placeholder || (isRangeMode() ? "Seleccionar rango..." : "Seleccionar fecha..."),
|
||||||
value: displayValue,
|
value: displayValue,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
icon: $.html("img", { src: iconCalendar, class: "opacity-40" }),
|
icon: $html("img", { src: iconCalendar, class: "opacity-40" }),
|
||||||
onclick: (e) => {
|
onclick: (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
isOpen(!isOpen());
|
isOpen(!isOpen());
|
||||||
@@ -414,46 +415,46 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
...rest,
|
...rest,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
$.if(isOpen, () =>
|
$if(isOpen, () =>
|
||||||
$.html(
|
$html(
|
||||||
"div",
|
"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",
|
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(),
|
onclick: (e) => e.stopPropagation(),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html("div", { class: "flex justify-between items-center mb-4 gap-1" }, [
|
$html("div", { class: "flex justify-between items-center mb-4 gap-1" }, [
|
||||||
$.html("div", { class: "flex gap-0.5" }, [
|
$html("div", { class: "flex gap-0.5" }, [
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(-1) },
|
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(-1) },
|
||||||
$.html("img", { src: iconLLeft, class: "opacity-40" }),
|
$html("img", { src: iconLLeft, class: "opacity-40" }),
|
||||||
),
|
),
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(-1) },
|
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(-1) },
|
||||||
$.html("img", { src: iconLeft, class: "opacity-40" }),
|
$html("img", { src: iconLeft, class: "opacity-40" }),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
$.html("span", { class: "font-bold uppercase flex-1 text-center" }, [
|
$html("span", { class: "font-bold uppercase flex-1 text-center" }, [
|
||||||
() => internalDate().toLocaleString("es-ES", { month: "short", year: "numeric" }),
|
() => internalDate().toLocaleString("es-ES", { month: "short", year: "numeric" }),
|
||||||
]),
|
]),
|
||||||
$.html("div", { class: "flex gap-0.5" }, [
|
$html("div", { class: "flex gap-0.5" }, [
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(1) },
|
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => move(1) },
|
||||||
$.html("img", { src: iconRight, class: "opacity-40" }),
|
$html("img", { src: iconRight, class: "opacity-40" }),
|
||||||
),
|
),
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(1) },
|
{ type: "button", class: "btn btn-ghost btn-xs px-1", onclick: () => moveYear(1) },
|
||||||
$.html("img", { src: iconRRight, class: "opacity-40" }),
|
$html("img", { src: iconRRight, class: "opacity-40" }),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
$.html("div", { class: "grid grid-cols-7 gap-1", onmouseleave: () => hoverDate(null) }, [
|
$html("div", { class: "grid grid-cols-7 gap-1", onmouseleave: () => hoverDate(null) }, [
|
||||||
...["L", "M", "X", "J", "V", "S", "D"].map((d) => $.html("div", { class: "text-[10px] opacity-40 font-bold text-center" }, d)),
|
...["L", "M", "X", "J", "V", "S", "D"].map((d) => $html("div", { class: "text-[10px] opacity-40 font-bold text-center" }, d)),
|
||||||
() => {
|
() => {
|
||||||
const d = internalDate();
|
const d = internalDate();
|
||||||
const year = d.getFullYear();
|
const year = d.getFullYear();
|
||||||
@@ -463,14 +464,14 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||||
|
|
||||||
const nodes = [];
|
const nodes = [];
|
||||||
for (let i = 0; i < offset; i++) nodes.push($.html("div"));
|
for (let i = 0; i < offset; i++) nodes.push($html("div"));
|
||||||
|
|
||||||
for (let i = 1; i <= daysInMonth; i++) {
|
for (let i = 1; i <= daysInMonth; i++) {
|
||||||
const date = new Date(year, month, i);
|
const date = new Date(year, month, i);
|
||||||
const dStr = formatDate(date);
|
const dStr = formatDate(date);
|
||||||
|
|
||||||
nodes.push(
|
nodes.push(
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
type: "button",
|
type: "button",
|
||||||
@@ -512,7 +513,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
$.if(isOpen, () => $.html("div", { class: "fixed inset-0 z-[90]", onclick: () => isOpen(false) })),
|
$if(isOpen, () => $html("div", { class: "fixed inset-0 z-[90]", onclick: () => isOpen(false) })),
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -534,8 +535,8 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
const getColor = () => val(value) || "#000000";
|
const getColor = () => val(value) || "#000000";
|
||||||
|
|
||||||
return $.html("div", { class: "relative w-fit" }, [
|
return $html("div", { class: "relative w-fit" }, [
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
type: "button",
|
type: "button",
|
||||||
@@ -547,27 +548,27 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
...rest,
|
...rest,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html("div", {
|
$html("div", {
|
||||||
class: "size-5 rounded-sm shadow-inner border border-black/10 shrink-0",
|
class: "size-5 rounded-sm shadow-inner border border-black/10 shrink-0",
|
||||||
style: () => `background-color: ${getColor()}`,
|
style: () => `background-color: ${getColor()}`,
|
||||||
}),
|
}),
|
||||||
label ? $.html("span", { class: "opacity-80" }, label) : null,
|
label ? $html("span", { class: "opacity-80" }, label) : null,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
$.if(isOpen, () =>
|
$if(isOpen, () =>
|
||||||
$.html(
|
$html(
|
||||||
"div",
|
"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",
|
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(),
|
onclick: (e) => e.stopPropagation(),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html(
|
$html(
|
||||||
"div",
|
"div",
|
||||||
{ class: "grid grid-cols-8 gap-1" },
|
{ class: "grid grid-cols-8 gap-1" },
|
||||||
palette.map((c) =>
|
palette.map((c) =>
|
||||||
$.html("button", {
|
$html("button", {
|
||||||
type: "button",
|
type: "button",
|
||||||
style: `background-color: ${c}`,
|
style: `background-color: ${c}`,
|
||||||
class: () => {
|
class: () => {
|
||||||
@@ -586,8 +587,8 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
$.if(isOpen, () =>
|
$if(isOpen, () =>
|
||||||
$.html("div", {
|
$html("div", {
|
||||||
class: "fixed inset-0 z-[100]",
|
class: "fixed inset-0 z-[100]",
|
||||||
onclick: () => isOpen(false),
|
onclick: () => isOpen(false),
|
||||||
}),
|
}),
|
||||||
@@ -598,26 +599,26 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
/** CHECKBOX */
|
/** CHECKBOX */
|
||||||
ui.CheckBox = (props) => {
|
ui.CheckBox = (props) => {
|
||||||
const { value, tooltip, toggle, ...rest } = props;
|
const { value, tooltip, toggle, ...rest } = props;
|
||||||
const checkEl = $.html("input", {
|
const checkEl = $html("input", {
|
||||||
...rest,
|
...rest,
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
class: () => (val(toggle) ? "toggle" : "checkbox"),
|
class: () => (val(toggle) ? "toggle" : "checkbox"),
|
||||||
checked: value
|
checked: value
|
||||||
});
|
});
|
||||||
|
|
||||||
const layout = $.html("label", { class: "label cursor-pointer justify-start gap-3" }, [
|
const layout = $html("label", { class: "label cursor-pointer justify-start gap-3" }, [
|
||||||
checkEl,
|
checkEl,
|
||||||
props.label ? $.html("span", { class: "label-text" }, props.label) : null,
|
props.label ? $html("span", { class: "label-text" }, props.label) : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return tooltip ? $.html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
|
return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** RADIO */
|
/** RADIO */
|
||||||
ui.Radio = (props) => {
|
ui.Radio = (props) => {
|
||||||
const { label, tooltip, value, ...rest } = props;
|
const { label, tooltip, value, ...rest } = props;
|
||||||
|
|
||||||
const radioEl = $.html("input", {
|
const radioEl = $html("input", {
|
||||||
...rest,
|
...rest,
|
||||||
type: "radio",
|
type: "radio",
|
||||||
class: joinClass("radio", props.class || props.class),
|
class: joinClass("radio", props.class || props.class),
|
||||||
@@ -628,19 +629,19 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
if (!label && !tooltip) return radioEl;
|
if (!label && !tooltip) return radioEl;
|
||||||
|
|
||||||
const layout = $.html("label", { class: "label cursor-pointer justify-start gap-3" }, [
|
const layout = $html("label", { class: "label cursor-pointer justify-start gap-3" }, [
|
||||||
radioEl,
|
radioEl,
|
||||||
label ? $.html("span", { class: "label-text" }, label) : null,
|
label ? $html("span", { class: "label-text" }, label) : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return tooltip ? $.html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
|
return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** RANGE */
|
/** RANGE */
|
||||||
ui.Range = (props) => {
|
ui.Range = (props) => {
|
||||||
const { label, tooltip, value, ...rest } = props;
|
const { label, tooltip, value, ...rest } = props;
|
||||||
|
|
||||||
const rangeEl = $.html("input", {
|
const rangeEl = $html("input", {
|
||||||
...rest,
|
...rest,
|
||||||
type: "range",
|
type: "range",
|
||||||
class: joinClass("range", props.class),
|
class: joinClass("range", props.class),
|
||||||
@@ -650,12 +651,12 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
if (!label && !tooltip) return rangeEl;
|
if (!label && !tooltip) return rangeEl;
|
||||||
|
|
||||||
const layout = $.html("div", { class: "flex flex-col gap-2" }, [
|
const layout = $html("div", { class: "flex flex-col gap-2" }, [
|
||||||
label ? $.html("span", { class: "label-text" }, label) : null,
|
label ? $html("span", { class: "label-text" }, label) : null,
|
||||||
rangeEl
|
rangeEl
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return tooltip ? $.html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
|
return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** MODAL */
|
/** MODAL */
|
||||||
@@ -663,24 +664,24 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const { title, buttons, open, ...rest } = props;
|
const { title, buttons, open, ...rest } = props;
|
||||||
const close = () => open(false);
|
const close = () => open(false);
|
||||||
|
|
||||||
return $.if(open, () =>
|
return $if(open, () =>
|
||||||
$.html("dialog", { ...rest, class: "modal modal-open" }, [
|
$html("dialog", { ...rest, class: "modal modal-open" }, [
|
||||||
$.html("div", { class: "modal-box" }, [
|
$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" }, title) : null,
|
||||||
typeof children === "function" ? children() : children,
|
typeof children === "function" ? children() : children,
|
||||||
$.html("div", { class: "modal-action flex gap-2" }, [
|
$html("div", { class: "modal-action flex gap-2" }, [
|
||||||
...(Array.isArray(buttons) ? buttons : [buttons]).filter(Boolean),
|
...(Array.isArray(buttons) ? buttons : [buttons]).filter(Boolean),
|
||||||
ui.Button({ onclick: close }, tt("close")()),
|
ui.Button({ onclick: close }, tt("close")()),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
$.html(
|
$html(
|
||||||
"form",
|
"form",
|
||||||
{
|
{
|
||||||
method: "dialog",
|
method: "dialog",
|
||||||
class: "modal-backdrop",
|
class: "modal-backdrop",
|
||||||
onclick: (e) => (e.preventDefault(), close()),
|
onclick: (e) => (e.preventDefault(), close()),
|
||||||
},
|
},
|
||||||
[$.html("button", {}, "close")],
|
[$html("button", {}, "close")],
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
@@ -691,7 +692,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const { data, options, class: className } = props;
|
const { data, options, class: className } = props;
|
||||||
let gridApi = null;
|
let gridApi = null;
|
||||||
|
|
||||||
const container = $.html("div", {
|
const container = $html("div", {
|
||||||
style: "height: 100%; width: 100%;",
|
style: "height: 100%; width: 100%;",
|
||||||
class: className,
|
class: className,
|
||||||
});
|
});
|
||||||
@@ -707,7 +708,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
container._cleanups.add(() => observer.disconnect());
|
container._cleanups.add(() => observer.disconnect());
|
||||||
|
|
||||||
const stopGrid = $.watch(() => {
|
const stopGrid = $watch(() => {
|
||||||
const dark = isDark();
|
const dark = isDark();
|
||||||
const agTheme = getTheme(dark);
|
const agTheme = getTheme(dark);
|
||||||
const rowData = val(data) || [];
|
const rowData = val(data) || [];
|
||||||
@@ -724,7 +725,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
});
|
});
|
||||||
container._cleanups.add(stopGrid);
|
container._cleanups.add(stopGrid);
|
||||||
|
|
||||||
const stopData = $.watch(() => {
|
const stopData = $watch(() => {
|
||||||
const rowData = val(data);
|
const rowData = val(data);
|
||||||
if (gridApi && Array.isArray(rowData)) {
|
if (gridApi && Array.isArray(rowData)) {
|
||||||
gridApi.setGridOption("rowData", rowData);
|
gridApi.setGridOption("rowData", rowData);
|
||||||
@@ -746,14 +747,14 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
ui.Dropdown = (props, children) => {
|
ui.Dropdown = (props, children) => {
|
||||||
const { label, icon, ...rest } = props;
|
const { label, icon, ...rest } = props;
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
class: () => `dropdown ${val(props.class) || props.class || ""}`,
|
class: () => `dropdown ${val(props.class) || props.class || ""}`,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html(
|
$html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
@@ -762,7 +763,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
},
|
},
|
||||||
[icon ? (typeof icon === "function" ? icon() : icon) : null, label ? (typeof label === "function" ? label() : label) : null],
|
[icon ? (typeof icon === "function" ? icon() : icon) : null, label ? (typeof label === "function" ? label() : label) : null],
|
||||||
),
|
),
|
||||||
$.html(
|
$html(
|
||||||
"ul",
|
"ul",
|
||||||
{
|
{
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
@@ -778,20 +779,20 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
ui.Accordion = (props, children) => {
|
ui.Accordion = (props, children) => {
|
||||||
const { title, name, open, ...rest } = props;
|
const { title, name, open, ...rest } = props;
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
class: joinClass("collapse collapse-arrow bg-base-200 mb-2", props.class || props.class),
|
class: joinClass("collapse collapse-arrow bg-base-200 mb-2", props.class || props.class),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html("input", {
|
$html("input", {
|
||||||
type: name ? "radio" : "checkbox",
|
type: name ? "radio" : "checkbox",
|
||||||
name: name,
|
name: name,
|
||||||
checked: open
|
checked: open
|
||||||
}),
|
}),
|
||||||
$.html("div", { class: "collapse-title text-xl font-medium" }, title),
|
$html("div", { class: "collapse-title text-xl font-medium" }, title),
|
||||||
$.html("div", { class: "collapse-content" }, children),
|
$html("div", { class: "collapse-content" }, children),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -801,17 +802,17 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const { items, ...rest } = props;
|
const { items, ...rest } = props;
|
||||||
const itemsSignal = typeof items === "function" ? items : () => items || [];
|
const itemsSignal = typeof items === "function" ? items : () => items || [];
|
||||||
|
|
||||||
return $.html("div", { ...rest, class: "flex flex-col gap-4 w-full" }, [
|
return $html("div", { ...rest, class: "flex flex-col gap-4 w-full" }, [
|
||||||
$.html(
|
$html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
role: "tablist",
|
role: "tablist",
|
||||||
class: joinClass("tabs tabs-box", props.class || props.class),
|
class: joinClass("tabs tabs-box", props.class || props.class),
|
||||||
},
|
},
|
||||||
$.for(
|
$for(
|
||||||
itemsSignal,
|
itemsSignal,
|
||||||
(it) =>
|
(it) =>
|
||||||
$.html(
|
$html(
|
||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
role: "tab",
|
role: "tab",
|
||||||
@@ -828,64 +829,64 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const active = itemsSignal().find((it) => val(it.active));
|
const active = itemsSignal().find((it) => val(it.active));
|
||||||
if (!active) return null;
|
if (!active) return null;
|
||||||
const content = val(active.content);
|
const content = val(active.content);
|
||||||
return $.html("div", { class: "p-4" }, [typeof content === "function" ? content() : content]);
|
return $html("div", { class: "p-4" }, [typeof content === "function" ? content() : content]);
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** BADGE */
|
/** BADGE */
|
||||||
ui.Badge = (props, children) => $.html("span", { ...props, class: joinClass("badge", props.class || props.class) }, children);
|
ui.Badge = (props, children) => $html("span", { ...props, class: joinClass("badge", props.class || props.class) }, children);
|
||||||
|
|
||||||
/** TOOLTIP */
|
/** TOOLTIP */
|
||||||
ui.Tooltip = (props, children) =>
|
ui.Tooltip = (props, children) =>
|
||||||
$.html("div", { ...props, class: joinClass("tooltip", props.class || props.class), "data-tip": props.tip }, children);
|
$html("div", { ...props, class: joinClass("tooltip", props.class || props.class), "data-tip": props.tip }, children);
|
||||||
|
|
||||||
/** NAVBAR */
|
/** NAVBAR */
|
||||||
ui.Navbar = (props, children) =>
|
ui.Navbar = (props, children) =>
|
||||||
$.html("div", { ...props, class: joinClass("navbar bg-base-100 shadow-sm px-4", props.class || props.class) }, children);
|
$html("div", { ...props, class: joinClass("navbar bg-base-100 shadow-sm px-4", props.class || props.class) }, children);
|
||||||
|
|
||||||
/** MENU */
|
/** MENU */
|
||||||
ui.Menu = (props) => {
|
ui.Menu = (props) => {
|
||||||
const renderItems = (items) =>
|
const renderItems = (items) =>
|
||||||
$.for(
|
$for(
|
||||||
() => items || [],
|
() => items || [],
|
||||||
(it) =>
|
(it) =>
|
||||||
$.html("li", {}, [
|
$html("li", {}, [
|
||||||
it.children
|
it.children
|
||||||
? $.html("details", { open: it.open }, [
|
? $html("details", { open: it.open }, [
|
||||||
$.html("summary", {}, [it.icon && $.html("span", { class: "mr-2" }, it.icon), it.label]),
|
$html("summary", {}, [it.icon && $html("span", { class: "mr-2" }, it.icon), it.label]),
|
||||||
$.html("ul", {}, renderItems(it.children)),
|
$html("ul", {}, renderItems(it.children)),
|
||||||
])
|
])
|
||||||
: $.html("a", { class: () => (val(it.active) ? "active" : ""), onclick: it.onclick }, [
|
: $html("a", { class: () => (val(it.active) ? "active" : ""), onclick: it.onclick }, [
|
||||||
it.icon && $.html("span", { class: "mr-2" }, it.icon),
|
it.icon && $html("span", { class: "mr-2" }, it.icon),
|
||||||
it.label,
|
it.label,
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
(it, i) => it.label || i,
|
(it, i) => it.label || i,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $.html("ul", { ...props, class: joinClass("menu bg-base-200 rounded-box", props.class || props.class) }, renderItems(props.items));
|
return $html("ul", { ...props, class: joinClass("menu bg-base-200 rounded-box", props.class || props.class) }, renderItems(props.items));
|
||||||
};
|
};
|
||||||
|
|
||||||
/** DRAWER */
|
/** DRAWER */
|
||||||
ui.Drawer = (props) =>
|
ui.Drawer = (props) =>
|
||||||
$.html("div", { class: joinClass("drawer", props.class || props.class) }, [
|
$html("div", { class: joinClass("drawer", props.class || props.class) }, [
|
||||||
$.html("input", {
|
$html("input", {
|
||||||
id: props.id,
|
id: props.id,
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
class: "drawer-toggle",
|
class: "drawer-toggle",
|
||||||
checked: props.open,
|
checked: props.open,
|
||||||
}),
|
}),
|
||||||
$.html("div", { class: "drawer-content" }, props.content),
|
$html("div", { class: "drawer-content" }, props.content),
|
||||||
$.html("div", { class: "drawer-side" }, [
|
$html("div", { class: "drawer-side" }, [
|
||||||
$.html("label", { for: props.id, class: "drawer-overlay", onclick: () => props.open?.(false) }),
|
$html("label", { for: props.id, class: "drawer-overlay", onclick: () => props.open?.(false) }),
|
||||||
$.html("div", { class: "min-h-full bg-base-200 w-80" }, props.side),
|
$html("div", { class: "min-h-full bg-base-200 w-80" }, props.side),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** FIELDSET */
|
/** FIELDSET */
|
||||||
ui.Fieldset = (props, children) =>
|
ui.Fieldset = (props, children) =>
|
||||||
$.html(
|
$html(
|
||||||
"fieldset",
|
"fieldset",
|
||||||
{
|
{
|
||||||
...props,
|
...props,
|
||||||
@@ -894,7 +895,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
[
|
[
|
||||||
() => {
|
() => {
|
||||||
const legendText = val(props.legend);
|
const legendText = val(props.legend);
|
||||||
return legendText ? $.html("legend", { class: "fieldset-legend font-bold" }, [legendText]) : null;
|
return legendText ? $html("legend", { class: "fieldset-legend font-bold" }, [legendText]) : null;
|
||||||
},
|
},
|
||||||
children,
|
children,
|
||||||
],
|
],
|
||||||
@@ -904,46 +905,46 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
ui.List = (props) => {
|
ui.List = (props) => {
|
||||||
const { items, header, render, keyFn, class: className } = props;
|
const { items, header, render, keyFn, class: className } = props;
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"ul",
|
"ul",
|
||||||
{
|
{
|
||||||
class: joinClass("list bg-base-100 rounded-box shadow-md", className),
|
class: joinClass("list bg-base-100 rounded-box shadow-md", className),
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.if(header, () => $.html("li", { class: "p-4 pb-2 text-xs opacity-60 tracking-wide" }, [val(header)])),
|
$if(header, () => $html("li", { class: "p-4 pb-2 text-xs opacity-60 tracking-wide" }, [val(header)])),
|
||||||
$.for(items, (item, index) => $.html("li", { class: "list-row" }, [render(item, index)]), keyFn),
|
$for(items, (item, index) => $html("li", { class: "list-row" }, [render(item, index)]), keyFn),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** STACK */
|
/** STACK */
|
||||||
ui.Stack = (props, children) => $.html("div", { ...props, class: joinClass("stack", props.class || props.class) }, children);
|
ui.Stack = (props, children) => $html("div", { ...props, class: joinClass("stack", props.class || props.class) }, children);
|
||||||
|
|
||||||
/** STAT */
|
/** STAT */
|
||||||
ui.Stat = (props) =>
|
ui.Stat = (props) =>
|
||||||
$.html("div", { ...props, class: joinClass("stat", props.class || props.class) }, [
|
$html("div", { ...props, class: joinClass("stat", props.class || props.class) }, [
|
||||||
props.icon && $.html("div", { class: "stat-figure text-secondary" }, props.icon),
|
props.icon && $html("div", { class: "stat-figure text-secondary" }, props.icon),
|
||||||
props.label && $.html("div", { class: "stat-title" }, props.label),
|
props.label && $html("div", { class: "stat-title" }, props.label),
|
||||||
$.html("div", { class: "stat-value" }, () => val(props.value) ?? props.value),
|
$html("div", { class: "stat-value" }, () => val(props.value) ?? props.value),
|
||||||
props.desc && $.html("div", { class: "stat-desc" }, props.desc),
|
props.desc && $html("div", { class: "stat-desc" }, props.desc),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** SWAP */
|
/** SWAP */
|
||||||
ui.Swap = (props) =>
|
ui.Swap = (props) =>
|
||||||
$.html("label", { class: joinClass("swap", props.class || props.class) }, [
|
$html("label", { class: joinClass("swap", props.class || props.class) }, [
|
||||||
$.html("input", {
|
$html("input", {
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
checked: props.value
|
checked: props.value
|
||||||
}),
|
}),
|
||||||
$.html("div", { class: "swap-on" }, props.on),
|
$html("div", { class: "swap-on" }, props.on),
|
||||||
$.html("div", { class: "swap-off" }, props.off),
|
$html("div", { class: "swap-off" }, props.off),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** INDICATOR */
|
/** INDICATOR */
|
||||||
ui.Indicator = (props, children) =>
|
ui.Indicator = (props, children) =>
|
||||||
$.html("div", { class: joinClass("indicator", props.class || props.class) }, [
|
$html("div", { class: joinClass("indicator", props.class || props.class) }, [
|
||||||
children,
|
children,
|
||||||
$.html("span", { class: joinClass("indicator-item badge", props.badgeClass) }, props.badge),
|
$html("span", { class: joinClass("indicator-item badge", props.badgeClass) }, props.badge),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** RATING */
|
/** RATING */
|
||||||
@@ -951,14 +952,14 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const { value, count = 5, mask = "mask-star", readonly = false, ...rest } = props;
|
const { value, count = 5, mask = "mask-star", readonly = false, ...rest } = props;
|
||||||
const ratingGroup = `rating-${Math.random().toString(36).slice(2, 7)}`;
|
const ratingGroup = `rating-${Math.random().toString(36).slice(2, 7)}`;
|
||||||
|
|
||||||
return $.html("div", {
|
return $html("div", {
|
||||||
...rest,
|
...rest,
|
||||||
class: () => `rating ${val(readonly) ? "pointer-events-none" : ""} ${props.class || ""}`,
|
class: () => `rating ${val(readonly) ? "pointer-events-none" : ""} ${props.class || ""}`,
|
||||||
},
|
},
|
||||||
Array.from({ length: val(count) }, (_, i) => {
|
Array.from({ length: val(count) }, (_, i) => {
|
||||||
const starValue = i + 1;
|
const starValue = i + 1;
|
||||||
|
|
||||||
return $.html("input", {
|
return $html("input", {
|
||||||
type: "radio",
|
type: "radio",
|
||||||
name: ratingGroup,
|
name: ratingGroup,
|
||||||
class: `mask ${mask}`,
|
class: `mask ${mask}`,
|
||||||
@@ -996,7 +997,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
const content = children || props.message;
|
const content = children || props.message;
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
@@ -1004,13 +1005,13 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
class: () => `alert ${typeClass()} ${val(soft) ? "alert-soft" : ""} ${props.class || ""}`,
|
class: () => `alert ${typeClass()} ${val(soft) ? "alert-soft" : ""} ${props.class || ""}`,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html("img", {
|
$html("img", {
|
||||||
src: icons[val(type)] || icons.info,
|
src: icons[val(type)] || icons.info,
|
||||||
class: "w-4 h-4 object-contain",
|
class: "w-4 h-4 object-contain",
|
||||||
alt: val(type),
|
alt: val(type),
|
||||||
}),
|
}),
|
||||||
$.html("div", { class: "flex-1" }, [$.html("span", {}, [typeof content === "function" ? content() : content])]),
|
$html("div", { class: "flex-1" }, [$html("span", {}, [typeof content === "function" ? content() : content])]),
|
||||||
props.actions ? $.html("div", { class: "flex-none" }, [typeof props.actions === "function" ? props.actions() : props.actions]) : null,
|
props.actions ? $html("div", { class: "flex-none" }, [typeof props.actions === "function" ? props.actions() : props.actions]) : null,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -1026,7 +1027,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
error: iconError,
|
error: iconError,
|
||||||
};
|
};
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"ul",
|
"ul",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
@@ -1034,7 +1035,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
`timeline ${val(vertical) ? "timeline-vertical" : "timeline-horizontal"} ${val(compact) ? "timeline-compact" : ""} ${props.class || ""}`,
|
`timeline ${val(vertical) ? "timeline-vertical" : "timeline-horizontal"} ${val(compact) ? "timeline-compact" : ""} ${props.class || ""}`,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.for(
|
$for(
|
||||||
items,
|
items,
|
||||||
(item, i) => {
|
(item, i) => {
|
||||||
const isFirst = i === 0;
|
const isFirst = i === 0;
|
||||||
@@ -1042,18 +1043,18 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
const itemType = item.type || "success";
|
const itemType = item.type || "success";
|
||||||
const renderSlot = (content) => (typeof content === "function" ? content() : content);
|
const renderSlot = (content) => (typeof content === "function" ? content() : content);
|
||||||
|
|
||||||
return $.html("li", { class: "flex-1" }, [
|
return $html("li", { class: "flex-1" }, [
|
||||||
!isFirst ? $.html("hr", { class: item.completed ? "bg-primary" : "" }) : null,
|
!isFirst ? $html("hr", { class: item.completed ? "bg-primary" : "" }) : null,
|
||||||
$.html("div", { class: "timeline-start" }, [renderSlot(item.title)]),
|
$html("div", { class: "timeline-start" }, [renderSlot(item.title)]),
|
||||||
$.html("div", { class: "timeline-middle" }, [
|
$html("div", { class: "timeline-middle" }, [
|
||||||
$.html("img", {
|
$html("img", {
|
||||||
src: icons[itemType] || item.icon || icons.success,
|
src: icons[itemType] || item.icon || icons.success,
|
||||||
class: "w-4 h-4 object-contain mx-1",
|
class: "w-4 h-4 object-contain mx-1",
|
||||||
alt: itemType,
|
alt: itemType,
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
$.html("div", { class: "timeline-end timeline-box shadow-sm" }, [renderSlot(item.detail)]),
|
$html("div", { class: "timeline-end timeline-box shadow-sm" }, [renderSlot(item.detail)]),
|
||||||
!isLast ? $.html("hr", { class: item.completed ? "bg-primary" : "" }) : null,
|
!isLast ? $html("hr", { class: item.completed ? "bg-primary" : "" }) : null,
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
(item, i) => item.id || i,
|
(item, i) => item.id || i,
|
||||||
@@ -1066,14 +1067,14 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
ui.Fab = (props) => {
|
ui.Fab = (props) => {
|
||||||
const { icon, label, actions = [], position = "bottom-6 right-6", ...rest } = props;
|
const { icon, label, actions = [], position = "bottom-6 right-6", ...rest } = props;
|
||||||
|
|
||||||
return $.html(
|
return $html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
...rest,
|
...rest,
|
||||||
class: () => `fab fixed ${val(position)} flex flex-col-reverse items-end gap-3 z-[100] ${props.class || ""}`,
|
class: () => `fab fixed ${val(position)} flex flex-col-reverse items-end gap-3 z-[100] ${props.class || ""}`,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html(
|
$html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
tabindex: 0,
|
tabindex: 0,
|
||||||
@@ -1084,9 +1085,9 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
),
|
),
|
||||||
|
|
||||||
...val(actions).map((act) =>
|
...val(actions).map((act) =>
|
||||||
$.html("div", { class: "flex items-center gap-3 transition-all duration-300" }, [
|
$html("div", { class: "flex items-center gap-3 transition-all duration-300" }, [
|
||||||
act.label ? $.html("span", { class: "badge badge-ghost shadow-sm whitespace-nowrap" }, act.label) : null,
|
act.label ? $html("span", { class: "badge badge-ghost shadow-sm whitespace-nowrap" }, act.label) : null,
|
||||||
$.html(
|
$html(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
type: "button",
|
type: "button",
|
||||||
@@ -1108,14 +1109,14 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
ui.Toast = (message, type = "alert-success", duration = 3500) => {
|
ui.Toast = (message, type = "alert-success", duration = 3500) => {
|
||||||
let container = document.getElementById("sigpro-toast-container");
|
let container = document.getElementById("sigpro-toast-container");
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = $.html("div", {
|
container = $html("div", {
|
||||||
id: "sigpro-toast-container",
|
id: "sigpro-toast-container",
|
||||||
class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col gap-2 pointer-events-none",
|
class: "fixed top-0 right-0 z-[9999] p-4 flex flex-col gap-2 pointer-events-none",
|
||||||
});
|
});
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
const toastHost = $.html("div", { style: "display: contents" });
|
const toastHost = $html("div", { style: "display: contents" });
|
||||||
container.appendChild(toastHost);
|
container.appendChild(toastHost);
|
||||||
|
|
||||||
let timeoutId;
|
let timeoutId;
|
||||||
@@ -1136,13 +1137,13 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ToastComponent = () => {
|
const ToastComponent = () => {
|
||||||
const el = $.html(
|
const el = $html(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: `alert alert-soft ${type} shadow-lg transition-all duration-300 translate-x-10 opacity-0 pointer-events-auto`,
|
class: `alert alert-soft ${type} shadow-lg transition-all duration-300 translate-x-10 opacity-0 pointer-events-auto`,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
$.html("span", typeof message === "function" ? message : () => message),
|
$html("span", typeof message === "function" ? message : () => message),
|
||||||
ui.Button({ class: "btn-xs btn-circle btn-ghost", onclick: close }, "✕"),
|
ui.Button({ class: "btn-xs btn-circle btn-ghost", onclick: close }, "✕"),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -1151,7 +1152,7 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
|
|
||||||
const instance = $.mount(ToastComponent, toastHost);
|
const instance = $mount(ToastComponent, toastHost);
|
||||||
|
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
timeoutId = setTimeout(close, duration);
|
timeoutId = setTimeout(close, duration);
|
||||||
@@ -1162,9 +1163,9 @@ export const UI = ($, defaultLang = "es") => {
|
|||||||
|
|
||||||
/** LOADING */
|
/** LOADING */
|
||||||
ui.Loading = (props) => {
|
ui.Loading = (props) => {
|
||||||
return $.if(props.$show, () =>
|
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("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" }),
|
$html("span", { class: "loading loading-spinner loading-lg text-primary" }),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
$.watch = (target, fn) => {
|
const $watch = (target, fn) => {
|
||||||
const isExplicit = Array.isArray(target);
|
const isExplicit = Array.isArray(target);
|
||||||
const callback = isExplicit ? fn : target;
|
const callback = isExplicit ? fn : target;
|
||||||
const depsInput = isExplicit ? target : null;
|
const depsInput = isExplicit ? target : null;
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
$.html = (tag, props = {}, content = []) => {
|
const $html = (tag, props = {}, content = []) => {
|
||||||
if (props instanceof Node || Array.isArray(props) || typeof props !== "object") {
|
if (props instanceof Node || Array.isArray(props) || typeof props !== "object") {
|
||||||
content = props; props = {};
|
content = props; props = {};
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@
|
|||||||
const isBindAttr = (k === "value" || k === "checked");
|
const isBindAttr = (k === "value" || k === "checked");
|
||||||
|
|
||||||
if (isInput && isBindAttr && isSignal) {
|
if (isInput && isBindAttr && isSignal) {
|
||||||
el._cleanups.add($.watch(() => {
|
el._cleanups.add($watch(() => {
|
||||||
const val = v();
|
const val = v();
|
||||||
if (el[k] !== val) el[k] = val;
|
if (el[k] !== val) el[k] = val;
|
||||||
}));
|
}));
|
||||||
@@ -209,7 +209,7 @@
|
|||||||
el.addEventListener(name, handler);
|
el.addEventListener(name, handler);
|
||||||
el._cleanups.add(() => el.removeEventListener(name, handler));
|
el._cleanups.add(() => el.removeEventListener(name, handler));
|
||||||
} else if (isSignal) {
|
} else if (isSignal) {
|
||||||
el._cleanups.add($.watch(() => {
|
el._cleanups.add($watch(() => {
|
||||||
const val = v();
|
const val = v();
|
||||||
if (k === "class") el.className = val || "";
|
if (k === "class") el.className = val || "";
|
||||||
else val == null ? el.removeAttribute(k) : el.setAttribute(k, val);
|
else val == null ? el.removeAttribute(k) : el.setAttribute(k, val);
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
const marker = document.createTextNode("");
|
const marker = document.createTextNode("");
|
||||||
el.appendChild(marker);
|
el.appendChild(marker);
|
||||||
let nodes = [];
|
let nodes = [];
|
||||||
el._cleanups.add($.watch(() => {
|
el._cleanups.add($watch(() => {
|
||||||
const res = c();
|
const res = c();
|
||||||
const next = (Array.isArray(res) ? res : [res]).map((i) =>
|
const next = (Array.isArray(res) ? res : [res]).map((i) =>
|
||||||
i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? "")
|
i?._isRuntime ? i.container : i instanceof Node ? i : document.createTextNode(i ?? "")
|
||||||
@@ -240,11 +240,11 @@
|
|||||||
return el;
|
return el;
|
||||||
};
|
};
|
||||||
|
|
||||||
$.if = (condition, thenVal, otherwiseVal = null) => {
|
const $if = (condition, thenVal, otherwiseVal = null) => {
|
||||||
const marker = document.createTextNode("");
|
const marker = document.createTextNode("");
|
||||||
const container = $.html("div", { style: "display:contents" }, [marker]);
|
const container = $html("div", { style: "display:contents" }, [marker]);
|
||||||
let current = null, last = null;
|
let current = null, last = null;
|
||||||
$.watch(() => {
|
$watch(() => {
|
||||||
const state = !!(typeof condition === "function" ? condition() : condition);
|
const state = !!(typeof condition === "function" ? condition() : condition);
|
||||||
if (state !== last) {
|
if (state !== last) {
|
||||||
last = state;
|
last = state;
|
||||||
@@ -259,11 +259,13 @@
|
|||||||
return container;
|
return container;
|
||||||
};
|
};
|
||||||
|
|
||||||
$.for = (source, render, keyFn) => {
|
$if.not = (condition, thenVal, otherwiseVal) => $if(() => !(typeof condition === "function" ? condition() : condition), thenVal, otherwiseVal);
|
||||||
|
|
||||||
|
const $for = (source, render, keyFn) => {
|
||||||
const marker = document.createTextNode("");
|
const marker = document.createTextNode("");
|
||||||
const container = $.html("div", { style: "display:contents" }, [marker]);
|
const container = $html("div", { style: "display:contents" }, [marker]);
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
$.watch(() => {
|
$watch(() => {
|
||||||
const items = (typeof source === "function" ? source() : source) || [];
|
const items = (typeof source === "function" ? source() : source) || [];
|
||||||
const newKeys = new Set();
|
const newKeys = new Set();
|
||||||
items.forEach((item, index) => {
|
items.forEach((item, index) => {
|
||||||
@@ -283,13 +285,13 @@
|
|||||||
return container;
|
return container;
|
||||||
};
|
};
|
||||||
|
|
||||||
$.router = (routes) => {
|
const $router = (routes) => {
|
||||||
const sPath = $(window.location.hash.replace(/^#/, "") || "/");
|
const sPath = $(window.location.hash.replace(/^#/, "") || "/");
|
||||||
window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/"));
|
window.addEventListener("hashchange", () => sPath(window.location.hash.replace(/^#/, "") || "/"));
|
||||||
const outlet = Div({ class: "router-outlet" });
|
const outlet = Div({ class: "router-outlet" });
|
||||||
let current = null;
|
let current = null;
|
||||||
|
|
||||||
$.watch([sPath], () => {
|
$watch([sPath], () => {
|
||||||
if (current) current.destroy();
|
if (current) current.destroy();
|
||||||
const path = sPath();
|
const path = sPath();
|
||||||
const route = routes.find(r => {
|
const route = routes.find(r => {
|
||||||
@@ -303,6 +305,7 @@
|
|||||||
route.path.split("/").filter(Boolean).forEach((p, i) => {
|
route.path.split("/").filter(Boolean).forEach((p, i) => {
|
||||||
if (p.startsWith(":")) params[p.slice(1)] = path.split("/").filter(Boolean)[i];
|
if (p.startsWith(":")) params[p.slice(1)] = path.split("/").filter(Boolean)[i];
|
||||||
});
|
});
|
||||||
|
if ($router.params) $router.params(params);
|
||||||
current = _view(() => {
|
current = _view(() => {
|
||||||
const res = route.component(params);
|
const res = route.component(params);
|
||||||
return typeof res === "function" ? res() : res;
|
return typeof res === "function" ? res() : res;
|
||||||
@@ -313,9 +316,12 @@
|
|||||||
return outlet;
|
return outlet;
|
||||||
};
|
};
|
||||||
|
|
||||||
$.go = (path) => (window.location.hash = path.replace(/^#?\/?/, "#/"));
|
$router.params = $({});
|
||||||
|
$router.to = (path) => (window.location.hash = path.replace(/^#?\/?/, "#/"));
|
||||||
|
$router.back = () => window.history.back();
|
||||||
|
$router.path = () => window.location.hash.replace(/^#/, "") || "/";
|
||||||
|
|
||||||
$.mount = (component, target) => {
|
const $mount = (component, target) => {
|
||||||
const el = typeof target === "string" ? document.querySelector(target) : target;
|
const el = typeof target === "string" ? document.querySelector(target) : target;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
if (MOUNTED_NODES.has(el)) MOUNTED_NODES.get(el).destroy();
|
if (MOUNTED_NODES.has(el)) MOUNTED_NODES.get(el).destroy();
|
||||||
@@ -325,18 +331,27 @@
|
|||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const core = { $, $if, $for, $watch, $mount, $router, $html };
|
||||||
|
|
||||||
|
for (const [name, fn] of Object.entries(core)) {
|
||||||
|
Object.defineProperty(window, name, {
|
||||||
|
value: fn,
|
||||||
|
writable: false,
|
||||||
|
configurable: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
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+/);
|
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) => {
|
tags.forEach((tagName) => {
|
||||||
const helperName = tagName.charAt(0).toUpperCase() + tagName.slice(1);
|
const helperName = tagName.charAt(0).toUpperCase() + tagName.slice(1);
|
||||||
|
|
||||||
Object.defineProperty(window, helperName, {
|
Object.defineProperty(window, helperName, {
|
||||||
value: (props, content) => $.html(tagName, props, content),
|
value: (props, content) => $html(tagName, props, content),
|
||||||
writable: false,
|
writable: false,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
enumerable: true
|
enumerable: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
window.$ = $;
|
|
||||||
})();
|
})();
|
||||||
export const { $ } = window;
|
export const { $, $watch, $html, $if, $for, $router, $mount } = window;
|
||||||
Reference in New Issue
Block a user