New export for UI

This commit is contained in:
2026-03-28 14:54:15 +01:00
parent 0809d4666c
commit 2b5b47ffe6
3 changed files with 814 additions and 869 deletions

View File

@@ -57,7 +57,7 @@ Explore the reactive building blocks of SigPro.
--- ---
## 🏗️ Element Constructors (Tags) ## Element Constructors (Tags)
SigPro provides **PascalCase** wrappers for all standard HTML5 tags (e.g., `Div`, `Span`, `Button`). SigPro provides **PascalCase** wrappers for all standard HTML5 tags (e.g., `Div`, `Span`, `Button`).

View File

@@ -1,6 +1,7 @@
# 🚀 Interactive Examples # Interactive Examples
Explore the power of SigPro through practical patterns. From basic reactivity to advanced composition. Explore the power of SigPro through practical patterns. From basic reactivity to advanced composition.
NOTE: Here we use DaisyUI for styles.
--- ---

View File

@@ -3,137 +3,69 @@
* Provides a set of reactive functional components, flow control and i18n. * Provides a set of reactive functional components, flow control and i18n.
*/ */
import { $, $if, $for, $watch, $html, $mount } from 'sigpro'; import { $, $if, $for, $watch, $html, $mount } from 'sigpro';
export const UI = (defaultLang = "es") => {
const ui = {};
// --- I18N CORE --- // --- I18N CORE ---
const i18n = { const i18n = {
es: { close: "Cerrar", confirm: "Confirmar", cancel: "Cancelar", search: "Buscar...", loading: "Cargando..." }, es: { close: "Cerrar", confirm: "Confirmar", cancel: "Cancelar", search: "Buscar...", loading: "Cargando..." },
en: { close: "Close", confirm: "Confirm", cancel: "Cancel", search: "Search...", loading: "Loading..." }, en: { close: "Close", confirm: "Confirm", cancel: "Cancel", search: "Search...", loading: "Loading..." },
}; };
const currentLocale = $(defaultLang); let currentLocale = $("es");
/** SET LOCALE */ /** SET LOCALE */
ui.SetLocale = (locale) => currentLocale(locale); export const SetLocale = (locale) => currentLocale(locale);
/** TRANSLATE */ /** TRANSLATE */
const tt = (key) => () => i18n[currentLocale()][key] || key; const tt = (key) => () => i18n[currentLocale()][key] || key;
// --- INTERNAL HELPERS --- // --- INTERNAL HELPERS ---
const val = (v) => (typeof v === "function" ? v() : v); const val = (v) => (typeof v === "function" ? v() : v);
const joinClass = (base, extra) => { const joinClass = (base, extra) => {
if (typeof extra === "function") { if (typeof extra === "function") {
return () => `${base} ${extra() || ""}`.trim(); return () => `${base} ${extra() || ""}`.trim();
} }
return `${base} ${extra || ""}`.trim(); return `${base} ${extra || ""}`.trim();
}; };
/** ICONS */ /** ICONS */
const iconShow = const iconShow =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADjSURBVDiN3dJNSgNBEAXgz4DZeAAVJ9tko2St3kaIFxAVt4KZeAD1GKKi7vQSydI/yHgALxAXU02GxniAFBR0v1ev+3V1sZSxjxtM8BM5wTX2/hNu4gFvOMI21iJ3cIwP3GMjF/dQ4RyraOMS34GPAmvjIrBeEnfwjoPGgSM8ooh8QtngB6Ep4BWnmaMqkY1LqqzmDC8tzNDK3/RHzLL9SloUYWfQIMuw3Yl8xrDBH6qbvZWALqbqBqVmlWF7GuKEDwPr5hbXcYdPnKBv/o39wL5wG7ULY1c9NGPzQRrjKrhli1/02zEjWyWMBwAAAABJRU5ErkJggg=="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADjSURBVDiN3dJNSgNBEAXgz4DZeAAVJ9tko2St3kaIFxAVt4KZeAD1GKKi7vQSydI/yHgALxAXU02GxniAFBR0v1ev+3V1sZSxjxtM8BM5wTX2/hNu4gFvOMI21iJ3cIwP3GMjF/dQ4RyraOMS34GPAmvjIrBeEnfwjoPGgSM8ooh8QtngB6Ep4BWnmaMqkY1LqqzmDC8tzNDK3/RHzLL9SloUYWfQIMuw3Yl8xrDBH6qbvZWALqbqBqVmlWF7GuKEDwPr5hbXcYdPnKBv/o39wL5wG7ULY1c9NGPzQRrjKrhli1/02zEjWyWMBwAAAABJRU5ErkJggg==";
const iconHide = const iconHide =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEDSURBVDiN1dK/K8VhFAbwD+VLGSxKcu9guSQ/Zils/gNkuaX4BxRZDTdklYU/QAaDlEVGGwu2Kz/uVbKJzWDwfuv1+jHz1Km3c85znuf0Hv4jxnD2W8MItnCJ5xAX2MQcHsOQL+jEAapYQD9aQwxiDy+B3JKSe1DHCpqQYQ0PeMJOpDyAmyAAirjGbDRwFYcoYCZSzjGP+8B1gqXEUT2QxyPlqaRnGceNeENzUswwil1MBocbSU9DCAXUUI6K25HtIo5QSVaooitP9OEO65iIbE+HXSvBVRbeNZQSR9pxGil3o83HNw5hEbfYR0dKFki5ci+u8OrzIQ1/R8xx7ocL+9t4B0HPOVXjoptxAAAAAElFTkSuQmCC"; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEDSURBVDiN1dK/K8VhFAbwD+VLGSxKcu9guSQ/Zils/gNkuaX4BxRZDTdklYU/QAaDlEVGGwu2Kz/uVbKJzWDwfuv1+jHz1Km3c85znuf0Hv4jxnD2W8MItnCJ5xAX2MQcHsOQL+jEAapYQD9aQwxiDy+B3JKSe1DHCpqQYQ0PeMJOpDyAmyAAirjGbDRwFYcoYCZSzjGP+8B1gqXEUT2QxyPlqaRnGceNeENzUswwil1MBocbSU9DCAXUUI6K25HtIo5QSVaooitP9OEO65iIbE+HXSvBVRbeNZQSR9pxGil3o83HNw5hEbfYR0dKFki5ci+u8OrzIQ1/R8xx7ocL+9t4B0HPOVXjoptxAAAAAElFTkSuQmCC";
const iconClose = const iconClose =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAESSURBVDiNtdO7LoRBHAXwXyhVG5ddEq9AgbXiskS1dOJS6DyDRKLmFRCvQY9aIi6FnpDsrkuiQCWKmS/5dmW/VXCSyWTm/GfmnPzP8A8oYBc3eEMd59iKXCZW8YpDzCOHHszgAE9Ya3V4EY8YzXhgAndYaib68YxiO4kYRg290Bk3t/GAvbiuII/7uJ7CGG5RxSCGcJrceh2LEkzGwnIctTgnGMdFWtZ7IimFcrykirkmrkvokI7WVn1lcD9wpdFCKfVyYmE2xRdFC4mCY2ykCgaEfp/gTGhbX4pfx1FaQUEIyW/bWBUC1oAFIUgjGYdLWgQpwTJesC/4z6Eb00JG6lhpJzGPHVziEx/CZ9qM3N/iGy1pNoTrsd1eAAAAAElFTkSuQmCC"; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAESSURBVDiNtdO7LoRBHAXwXyhVG5ddEq9AgbXiskS1dOJS6DyDRKLmFRCvQY9aIi6FnpDsrkuiQCWKmS/5dmW/VXCSyWTm/GfmnPzP8A8oYBc3eEMd59iKXCZW8YpDzCOHHszgAE9Ya3V4EY8YzXhgAndYaib68YxiO4kYRg290Bk3t/GAvbiuII/7uJ7CGG5RxSCGcJrceh2LEkzGwnIctTgnGMdFWtZ7IimFcrykirkmrkvokI7WVn1lcD9wpdFCKfVyYmE2xRdFC4mCY2ykCgaEfp/gTGhbX4pfx1FaQUEIyW/bWBUC1oAFIUgjGYdLWgQpwTJesC/4z6Eb00JG6lhpJzGPHVziEx/CZ9qM3N/iGy1pNoTrsd1eAAAAAElFTkSuQmCC";
const iconCalendar = const iconCalendar =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAACLSURBVDiN7dO9CQJBFEXhb38K0FwQrMNEVpuwB0NjrcYabECsQk0sQ1mTF4zIjrgmBh54MMx998AEwzOrmC5e8gJjbDHCJO7PHYI0v2JT4Ig9DljGwq5DkOZTLOCOMoIhBpknpHmFWx3ldaaUo6oTc2/ab7rl+508f8GvCC5oenTn4tM1cWg/nBNmD4fBH/Kfvt2TAAAAAElFTkSuQmCC"; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAACLSURBVDiN7dO9CQJBFEXhb38K0FwQrMNEVpuwB0NjrcYabECsQk0sQ1mTF4zIjrgmBh54MMx998AEwzOrmC5e8gJjbDHCJO7PHYI0v2JT4Ig9DljGwq5DkOZTLOCOMoIhBpknpHmFWx3ldaaUo6oTc2/ab7rl+508f8GvCC5oenTn4tM1cWg/nBNmD4fBH/Kfvt2TAAAAAElFTkSuQmCC";
const iconLock = const iconLock =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAWQAAAFkBqp2phgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAACQSURBVDiN7dKxDcJQDATQJ0YgXQQ1bAgDEIZBETPQwjakIjRQ8CMSyR8SiZKTrvHZd/r+JsYSNZrEI1ZR4ywzfElcJ55xwiITOECNTVDf4jDGoEEZ1Etcxxg8pmjRDiahb7BH20uKKPVUkVmL+YjQArdI+PT2bO9Pd/A34O71Rd9QeN/LAFUSckfUscWuG3oCgP8nrDH6T5AAAAAASUVORK5CYII="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAWQAAAFkBqp2phgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAACQSURBVDiN7dKxDcJQDATQJ0YgXQQ1bAgDEIZBETPQwjakIjRQ8CMSyR8SiZKTrvHZd/r+JsYSNZrEI1ZR4ywzfElcJ55xwiITOECNTVDf4jDGoEEZ1Etcxxg8pmjRDiahb7BH20uKKPVUkVmL+YjQArdI+PT2bO9Pd/A34O71Rd9QeN/LAFUSckfUscWuG3oCgP8nrDH6T5AAAAAASUVORK5CYII=";
const iconAbc = const iconAbc =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAB2AAAAdgFOeyYIAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAMRJREFUOI3t0bFKAmAUBeAPURD1HQwUTKPJEmzQoSWQcKpVfIuWdvU9WnqNhsYWBx0a2lvLSMKGbvQ7SO564HA497/3cu/92SPFAS5QDN9CftviDhZYYRpNPtH/rzATOsQT6jhCFzmc4DTJL6AX067hPiimuAr95RglzMJ/4AyyUXSMw3iEauhN6C0eUEMFAyzTFZ7xiOvwL3jbsPYSr3hPg3dB/o43SVYY+TnsPPwXztMG5SDr39dGM8kr4RKNDdPtJL4BNXEmsdKC+S4AAAAASUVORK5CYII="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAB2AAAAdgFOeyYIAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAMRJREFUOI3t0bFKAmAUBeAPURD1HQwUTKPJEmzQoSWQcKpVfIuWdvU9WnqNhsYWBx0a2lvLSMKGbvQ7SO564HA497/3cu/92SPFAS5QDN9CftviDhZYYRpNPtH/rzATOsQT6jhCFzmc4DTJL6AX067hPiimuAr95RglzMJ/4AyyUXSMw3iEauhN6C0eUEMFAyzTFZ7xiOvwL3jbsPYSr3hPg3dB/o43SVYY+TnsPPwXztMG5SDr39dGM8kr4RKNDdPtJL4BNXEmsdKC+S4AAAAASUVORK5CYII=";
const icon123 = const icon123 =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAB2AAAAdgFOeyYIAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAMxJREFUOI3t0bFKwlEUBvBfmmBEr1APIDZJ9AJJQyAIvkGP0C4uQruza+DUmuIc9AC9gBG4Nmpkw/8IB3Vw1w8u95zvnvPde77LEeUUV9HAF67QRA2nmMf5A+o4x3cWOsMYy8j7WMX6jaYbLBL/mAWe8RcHm1ihs8G94gVKQQzwlAouMcQo8p/Y28HdYpYFZmsi0MVdxD1MdrxsC500wijdvgtbI1AYtDbxMwkuFAZmE1uYwkkSqOIaHyHcxEU0vUXNPSqKr37fZ6xDwD9DPS0OyHjQHQAAAABJRU5ErkJggg=="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAB2AAAAdgFOeyYIAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAMxJREFUOI3t0bFKwlEUBvBfmmBEr1APIDZJ9AJJQyAIvkGP0C4uQruza+DUmuIc9AC9gBG4Nmpkw/8IB3Vw1w8u95zvnvPde77LEeUUV9HAF67QRA2nmMf5A+o4x3cWOsMYy8j7WMX6jaYbLBL/mAWe8RcHm1ihs8G94gVKQQzwlAouMcQo8p/Y28HdYpYFZmsi0MVdxD1MdrxsC500wijdvgtbI1AYtDbxMwkuFAZmE1uYwkkSqOIaHyHcxEU0vUXNPSqKr37fZ6xDwD9DPS0OyHjQHQAAAABJRU5ErkJggg==";
const iconMail = const iconMail =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC4SURBVDiNxdIxagJRFIXhLzLFBNJYaJslSEylWOhq3IorMGQ16SyjYCFiZWU5pTaDFvOUyTAZ8RHID69555577oXLf/OEGaY4R3g/4IhORHg3eOXYYvSAeRQ8OWQYYoNPvDQYnxUr7zBB1grCAv3QbIlxjXmAb7Txhq+rkFUKq9NUU8vcJiizwDtOWGEdmvTKqT+61H0GXsP7jSxpEGF/R1e3wkO0FBeVRnhTSBTneBB3yvOI4D/mAnvrIwKM5s4AAAAAAElFTkSuQmCC"; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAC4SURBVDiNxdIxagJRFIXhLzLFBNJYaJslSEylWOhq3IorMGQ16SyjYCFiZWU5pTaDFvOUyTAZ8RHID69555577oXLf/OEGaY4R3g/4IhORHg3eOXYYvSAeRQ8OWQYYoNPvDQYnxUr7zBB1grCAv3QbIlxjXmAb7Txhq+rkFUKq9NUU8vcJiizwDtOWGEdmvTKqT+61H0GXsP7jSxpEGF/R1e3wkO0FBeVRnhTSBTneBB3yvOI4D/mAnvrIwKM5s4AAAAAAElFTkSuQmCC";
const iconInfo = const iconInfo =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAASVJREFUOI190r0uhFEQBuBnVxaF2PUTCkFchV0SV6BQi0rEbShFlCqNktJP0Iqf3i3YVSlXVEQozojP8e2+ySSTed+ZMzNnKnpjCFPhv+C9j/YPlnCBV3TCujhHq19iFftoYxOjBa4esTb2QvsP+7jFWJ9HxnEXRf5gGU9Z8gKucBl+sUgHTahE8AJnOCoIT/AcmhmsF7gtrGINBqWFFWcmLXMUhzjIuEbk1GA+2i/DNh4wUsK1MVfFV2GUHJO4xlsPHr8j1Eu44bAcDek2agP4lDZaxWMm3MEKbrL4hjT/8U+gJc00nglnw4qYkL5xMW9rTzqSvEiefI/dMrIaRTrSPzcKXCNinUguPeUfNKWj6kqH9Bz+aVnbvb6PtKTp8F/wUSb6Bu5YN5n7ff0kAAAAAElFTkSuQmCC"; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAASVJREFUOI190r0uhFEQBuBnVxaF2PUTCkFchV0SV6BQi0rEbShFlCqNktJP0Iqf3i3YVSlXVEQozojP8e2+ySSTed+ZMzNnKnpjCFPhv+C9j/YPlnCBV3TCujhHq19iFftoYxOjBa4esTb2QvsP+7jFWJ9HxnEXRf5gGU9Z8gKucBl+sUgHTahE8AJnOCoIT/AcmhmsF7gtrGINBqWFFWcmLXMUhzjIuEbk1GA+2i/DNh4wUsK1MVfFV2GUHJO4xlsPHr8j1Eu44bAcDek2agP4lDZaxWMm3MEKbrL4hjT/8U+gJc00nglnw4qYkL5xMW9rTzqSvEiefI/dMrIaRTrSPzcKXCNinUguPeUfNKWj6kqH9Bz+aVnbvb6PtKTp8F/wUSb6Bu5YN5n7ff0kAAAAAElFTkSuQmCC";
const iconSuccess = const iconSuccess =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAQtJREFUOI2F0jFOAlEQBuAPImoFqyTa6TEEbfUihruYDYfwCAg3UDsTY20na0VjgqUWWuxgHsuy/skk82bmn/fPm9eyHXs4Cn+Br4baNZxjhk8UYUtMMWwitjHGHNfoJrlexObIo3YDY9zjoOGSQzxEkzVc4O0fctqkwCANzkJiE9LmI9ytDrvKB+tWGQnylIAsOB04VcrfdluO55CeYo6THfygVUne4jX8S1zho1LTDu7fCL2KxCe8oF8zUqb8G51VYGrzEffD6jDCJA0MY6bqnHXoK9d4Vk3kyk/S1KSPR9zUJdvRpAiJWZLLIlYEufYrrzBQ7nyJ97ClcuYN2dX1pejgOPwFvuuKfgHXiDR+HL1j1AAAAABJRU5ErkJggg=="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAQtJREFUOI2F0jFOAlEQBuAPImoFqyTa6TEEbfUihruYDYfwCAg3UDsTY20na0VjgqUWWuxgHsuy/skk82bmn/fPm9eyHXs4Cn+Br4baNZxjhk8UYUtMMWwitjHGHNfoJrlexObIo3YDY9zjoOGSQzxEkzVc4O0fctqkwCANzkJiE9LmI9ytDrvKB+tWGQnylIAsOB04VcrfdluO55CeYo6THfygVUne4jX8S1zho1LTDu7fCL2KxCe8oF8zUqb8G51VYGrzEffD6jDCJA0MY6bqnHXoK9d4Vk3kyk/S1KSPR9zUJdvRpAiJWZLLIlYEufYrrzBQ7nyJ97ClcuYN2dX1pejgOPwFvuuKfgHXiDR+HL1j1AAAAABJRU5ErkJggg==";
const iconError = const iconError =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAARZJREFUOI2V0j1KQ1EQBeDPp4lWRiMoKVyAK9AoiLgJGytxD9oJNhKyDyvBnw2IugC3YGKVRk1KRbR48yC5vjzwwIHL3DPnzp2ZGdMxj9U4D/BZoZ3ANu4wQj84xC3aVYkZuujhCItjd42I9dAJ7R908YDlikeaeAyTCezgpST5IJia9LFVlA0nOMd7It4IjuMttKeFQR17uKooPcUV9lHL0ArX0T8MPqLa1hx+MDNFWDX7LHLV4/VGiWghmGJJvhu1WXzLO5rhORGeYRf3SfwQNVwWgbZ8SZqJcD04jhX5GDfTsjryJUlN0uQnXJRdZmHSx7H8nwWWItaP5NJVLrCFG3mTXoNDXJeVPW185E1ai/MAX2WiX9S3NSPYbj+uAAAAAElFTkSuQmCC"; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAARZJREFUOI2V0j1KQ1EQBeDPp4lWRiMoKVyAK9AoiLgJGytxD9oJNhKyDyvBnw2IugC3YGKVRk1KRbR48yC5vjzwwIHL3DPnzp2ZGdMxj9U4D/BZoZ3ANu4wQj84xC3aVYkZuujhCItjd42I9dAJ7R908YDlikeaeAyTCezgpST5IJia9LFVlA0nOMd7It4IjuMttKeFQR17uKooPcUV9lHL0ArX0T8MPqLa1hx+MDNFWDX7LHLV4/VGiWghmGJJvhu1WXzLO5rhORGeYRf3SfwQNVwWgbZ8SZqJcD04jhX5GDfTsjryJUlN0uQnXJRdZmHSx7H8nwWWItaP5NJVLrCFG3mTXoNDXJeVPW185E1ai/MAX2WiX9S3NSPYbj+uAAAAAElFTkSuQmCC";
const iconWarning = const iconWarning =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAARJJREFUOI2l0r8uRFEQBvAfu9glwUYiUaxHUEl0VDpKeq+wpZBINAqFRHgTKg0tCSqVhmKDEM1u/Esodm725rq7iC+ZzMnM982ZmXP4JwpdchWsYBrXeMkj9XQQV3GEi+BMYR63v+mqiDPUUrEaTiP3I1ZxEOcySnE+jFxXVPEQPimWiCYzOdCbKbCFPe1Z+8PgBvvBycVMCIdSsY2wBEPBmcnrYBtraKRib2EJGljHjswLLuI8Z6SS9hLTl15iIR08wZLv2AzLYjk0YATP8n9lVWbrgUJohosYxCdG8Zghdvp5ldCUi6hrPd0VjvGEVzTxEYLkogGMYQ67uEtvcgKzGA8y9IV/D9/Evdb89Q7d/Q1fB8U0mpUmzV0AAAAASUVORK5CYII="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAnXAAAJ1wGxbhe3AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAARJJREFUOI2l0r8uRFEQBvAfu9glwUYiUaxHUEl0VDpKeq+wpZBINAqFRHgTKg0tCSqVhmKDEM1u/Esodm725rq7iC+ZzMnM982ZmXP4JwpdchWsYBrXeMkj9XQQV3GEi+BMYR63v+mqiDPUUrEaTiP3I1ZxEOcySnE+jFxXVPEQPimWiCYzOdCbKbCFPe1Z+8PgBvvBycVMCIdSsY2wBEPBmcnrYBtraKRib2EJGljHjswLLuI8Z6SS9hLTl15iIR08wZLv2AzLYjk0YATP8n9lVWbrgUJohosYxCdG8Zghdvp5ldCUi6hrPd0VjvGEVzTxEYLkogGMYQ67uEtvcgKzGA8y9IV/D9/Evdb89Q7d/Q1fB8U0mpUmzV0AAAAASUVORK5CYII=";
const iconLeft = const iconLeft =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABfSURBVDiNY2AY8oCZSHWxDAwMEgwMDHfJsaSAgYHhH9QQsjT/Z2BgKKe75gQGiLMLCSlkwiHOSI6t6ADmhYoBN6SIARIeidgkiUlIxxkYGB4xMDB8YmBguE6JSwYpAACvLRHTKwPjZgAAAABJRU5ErkJggg=="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABfSURBVDiNY2AY8oCZSHWxDAwMEgwMDHfJsaSAgYHhH9QQsjT/Z2BgKKe75gQGiLMLCSlkwiHOSI6t6ADmhYoBN6SIARIeidgkiUlIxxkYGB4xMDB8YmBguE6JSwYpAACvLRHTKwPjZgAAAABJRU5ErkJggg==";
const iconRight = const iconRight =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABNSURBVDiN3dAxCoAwFATRh3fU2oAHiDbi5Y1F2jT+gKLbzyy7/DYjUo8g4cTWI8koOF6XrOqc5ifDDVGJthfsj8OLujtHYJgwR+GP5QKMxA9/SolDQgAAAABJRU5ErkJggg=="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABNSURBVDiN3dAxCoAwFATRh3fU2oAHiDbi5Y1F2jT+gKLbzyy7/DYjUo8g4cTWI8koOF6XrOqc5ifDDVGJthfsj8OLujtHYJgwR+GP5QKMxA9/SolDQgAAAABJRU5ErkJggg==";
const iconLLeft = const iconLLeft =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABlSURBVDiN3ZLBDUBAEEUfmtCchA5woUMlOO1FCQrAwbqwf8eFhHd7mfzJn2Tg82TGvABywAmPUgOLD4XcDK9AJ/y5cOlrNsIvpCdPDL/FUbkX/t6Slv3+SjgQf6QBmIAZGAP+FzZJViOd89x8pAAAAABJRU5ErkJggg=="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABlSURBVDiN3ZLBDUBAEEUfmtCchA5woUMlOO1FCQrAwbqwf8eFhHd7mfzJn2Tg82TGvABywAmPUgOLD4XcDK9AJ/y5cOlrNsIvpCdPDL/FUbkX/t6Slv3+SjgQf6QBmIAZGAP+FzZJViOd89x8pAAAAABJRU5ErkJggg==";
const iconRRight = const iconRRight =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABmSURBVDiN3dGxCoAgEMbxfz1dL1BTREJzmUv08trgDYcg6VCD3/YD7zvkoLmMgFEegLmmwAAecOJVvNeUWCAAt7IHjt9LThkyiRf9qC8oCom70u0BuDL+bngj/tNm/JqJePucW8wDvGYdzT0nMUkAAAAASUVORK5CYII="; "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAdgAAAHYBTnsmCAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAABmSURBVDiN3dGxCoAgEMbxfz1dL1BTREJzmUv08trgDYcg6VCD3/YD7zvkoLmMgFEegLmmwAAecOJVvNeUWCAAt7IHjt9LThkyiRf9qC8oCom70u0BuDL+bngj/tNm/JqJePucW8wDvGYdzT0nMUkAAAAASUVORK5CYII=";
/** REQ */ // --- UI COMPONENTS ---
ui.Request = (url, payload = null, options = {}) => {
const data = $(null),
loading = $(false),
error = $(null),
success = $(false);
let abortController = null;
const execute = async (customPayload = null) => { /** BUTTON */
const targetUrl = val(url); export const Button = (props, children) => {
if (!targetUrl) return;
if (abortController) abortController.abort();
abortController = new AbortController();
loading(true);
error(null);
success(false);
try {
const bodyData = customPayload || payload;
const res = await fetch(targetUrl, {
method: options.method || (bodyData ? "POST" : "GET"),
headers: { "Content-Type": "application/json", ...options.headers },
body: bodyData ? JSON.stringify(bodyData) : null,
signal: abortController.signal,
...options,
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
let json = await res.json();
if (typeof options.transform === "function") json = options.transform(json);
data(json);
success(true);
} catch (err) {
if (err.name !== "AbortError") error(err.message);
} finally {
loading(false);
}
};
$(() => {
execute();
return () => abortController?.abort();
});
return { data, loading, error, success, reload: (p) => execute(p) };
};
/** RESPONSE */
ui.Response = (reqObj, renderFn) =>
$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.error, () =>
$html("div", { role: "alert", class: "alert alert-error" }, [
$html("span", {}, reqObj.error()),
ui.Button({ class: "btn-xs btn-ghost border-current", onclick: () => reqObj.reload() }, "Retry"),
]),
),
$if(reqObj.success, () => {
const current = reqObj.data();
return current !== null ? renderFn(current) : null;
}),
]);
// --- UI COMPONENTS ---
/** BUTTON */
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",
@@ -156,10 +88,10 @@ export const UI = (defaultLang = "es") => {
]); ]);
} }
return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, out) : out; return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, out) : out;
}; };
/** INPUT */ /** INPUT */
ui.Input = (props) => { export const Input = (props) => {
const { label, tip, value, error, isSearch, icon, type = "text", ...rest } = props; const { label, tip, value, error, isSearch, icon, type = "text", ...rest } = props;
const isPassword = type === "password"; const isPassword = type === "password";
const visible = $(false); const visible = $(false);
@@ -221,10 +153,10 @@ export const UI = (defaultLang = "es") => {
() => (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),
], ],
); );
}; };
/** SELECT */ /** SELECT */
ui.Select = (props) => { export const Select = (props) => {
const { label, options, value, ...rest } = props; const { label, options, value, ...rest } = props;
const selectEl = $html( const selectEl = $html(
@@ -252,10 +184,10 @@ 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 */
ui.Autocomplete = (props) => { export const Autocomplete = (props) => {
const { options = [], value, onSelect, label, placeholder, ...rest } = props; const { options = [], value, onSelect, label, placeholder, ...rest } = props;
const query = $(val(value) || ""); const query = $(val(value) || "");
@@ -298,7 +230,7 @@ export const UI = (defaultLang = "es") => {
}; };
return $html("div", { class: "relative w-full" }, [ return $html("div", { class: "relative w-full" }, [
ui.Input({ Input({
label, label,
placeholder: placeholder || tt("search")(), placeholder: placeholder || tt("search")(),
value: query, value: query,
@@ -341,10 +273,10 @@ export const UI = (defaultLang = "es") => {
], ],
), ),
]); ]);
}; };
/** DATEPICKER */ /** DATEPICKER */
ui.Datepicker = (props) => { export const Datepicker = (props) => {
const { value, range, label, placeholder, ...rest } = props; const { value, range, label, placeholder, ...rest } = props;
const isOpen = $(false); const isOpen = $(false);
@@ -402,7 +334,7 @@ export const UI = (defaultLang = "es") => {
}; };
return $html("div", { class: "relative w-full" }, [ return $html("div", { class: "relative w-full" }, [
ui.Input({ Input({
label, label,
placeholder: placeholder || (isRangeMode() ? "Seleccionar rango..." : "Seleccionar fecha..."), placeholder: placeholder || (isRangeMode() ? "Seleccionar rango..." : "Seleccionar fecha..."),
value: displayValue, value: displayValue,
@@ -515,10 +447,10 @@ 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) })),
]); ]);
}; };
/** COLORPICKER */ /** COLORPICKER */
ui.Colorpicker = (props) => { export const Colorpicker = (props) => {
const { value, label, ...rest } = props; const { value, label, ...rest } = props;
const isOpen = $(false); const isOpen = $(false);
@@ -594,10 +526,10 @@ export const UI = (defaultLang = "es") => {
}), }),
), ),
]); ]);
}; };
/** CHECKBOX */ /** CHECKBOX */
ui.CheckBox = (props) => { export const CheckBox = (props) => {
const { value, tooltip, toggle, ...rest } = props; const { value, tooltip, toggle, ...rest } = props;
const checkEl = $html("input", { const checkEl = $html("input", {
...rest, ...rest,
@@ -612,10 +544,10 @@ export const UI = (defaultLang = "es") => {
]); ]);
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) => { export const Radio = (props) => {
const { label, tooltip, value, ...rest } = props; const { label, tooltip, value, ...rest } = props;
const radioEl = $html("input", { const radioEl = $html("input", {
@@ -635,10 +567,10 @@ export const UI = (defaultLang = "es") => {
]); ]);
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) => { export const Range = (props) => {
const { label, tooltip, value, ...rest } = props; const { label, tooltip, value, ...rest } = props;
const rangeEl = $html("input", { const rangeEl = $html("input", {
@@ -657,10 +589,10 @@ export const UI = (defaultLang = "es") => {
]); ]);
return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout; return tooltip ? $html("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
}; };
/** MODAL */ /** MODAL */
ui.Modal = (props, children) => { export const Modal = (props, children) => {
const { title, buttons, open, ...rest } = props; const { title, buttons, open, ...rest } = props;
const close = () => open(false); const close = () => open(false);
@@ -671,7 +603,7 @@ export const UI = (defaultLang = "es") => {
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")()), Button({ onclick: close }, tt("close")()),
]), ]),
]), ]),
$html( $html(
@@ -685,10 +617,10 @@ export const UI = (defaultLang = "es") => {
), ),
]), ]),
); );
}; };
/** GRID */ /** GRID */
ui.Grid = (props) => { export const Grid = (props) => {
const { data, options, class: className } = props; const { data, options, class: className } = props;
let gridApi = null; let gridApi = null;
@@ -741,10 +673,10 @@ export const UI = (defaultLang = "es") => {
}); });
return container; return container;
}; };
/** DROPDOWN */ /** DROPDOWN */
ui.Dropdown = (props, children) => { export const Dropdown = (props, children) => {
const { label, icon, ...rest } = props; const { label, icon, ...rest } = props;
return $html( return $html(
@@ -773,10 +705,10 @@ export const UI = (defaultLang = "es") => {
), ),
], ],
); );
}; };
/** ACCORDION */ /** ACCORDION */
ui.Accordion = (props, children) => { export const Accordion = (props, children) => {
const { title, name, open, ...rest } = props; const { title, name, open, ...rest } = props;
return $html( return $html(
@@ -795,10 +727,10 @@ export const UI = (defaultLang = "es") => {
$html("div", { class: "collapse-content" }, children), $html("div", { class: "collapse-content" }, children),
], ],
); );
}; };
/** TABS */ /** TABS */
ui.Tabs = (props) => { export const Tabs = (props) => {
const { items, ...rest } = props; const { items, ...rest } = props;
const itemsSignal = typeof items === "function" ? items : () => items || []; const itemsSignal = typeof items === "function" ? items : () => items || [];
@@ -832,21 +764,21 @@ export const UI = (defaultLang = "es") => {
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); export const Badge = (props, children) => $html("span", { ...props, class: joinClass("badge", props.class || props.class) }, children);
/** TOOLTIP */ /** TOOLTIP */
ui.Tooltip = (props, children) => export const 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) => export const 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) => { export const Menu = (props) => {
const renderItems = (items) => const renderItems = (items) =>
$for( $for(
() => items || [], () => items || [],
@@ -866,10 +798,10 @@ export const UI = (defaultLang = "es") => {
); );
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) => export const 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,
@@ -884,8 +816,8 @@ export const UI = (defaultLang = "es") => {
]), ]),
]); ]);
/** FIELDSET */ /** FIELDSET */
ui.Fieldset = (props, children) => export const Fieldset = (props, children) =>
$html( $html(
"fieldset", "fieldset",
{ {
@@ -901,8 +833,8 @@ export const UI = (defaultLang = "es") => {
], ],
); );
/** LIST */ /** LIST */
ui.List = (props) => { export const List = (props) => {
const { items, header, render, keyFn, class: className } = props; const { items, header, render, keyFn, class: className } = props;
return $html( return $html(
@@ -915,13 +847,13 @@ export const UI = (defaultLang = "es") => {
$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); export const Stack = (props, children) => $html("div", { ...props, class: joinClass("stack", props.class || props.class) }, children);
/** STAT */ /** STAT */
ui.Stat = (props) => export const 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),
@@ -929,8 +861,8 @@ export const UI = (defaultLang = "es") => {
props.desc && $html("div", { class: "stat-desc" }, props.desc), props.desc && $html("div", { class: "stat-desc" }, props.desc),
]); ]);
/** SWAP */ /** SWAP */
ui.Swap = (props) => export const 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",
@@ -940,15 +872,15 @@ export const UI = (defaultLang = "es") => {
$html("div", { class: "swap-off" }, props.off), $html("div", { class: "swap-off" }, props.off),
]); ]);
/** INDICATOR */ /** INDICATOR */
ui.Indicator = (props, children) => export const 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 */
ui.Rating = (props) => { export const Rating = (props) => {
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)}`;
@@ -972,10 +904,10 @@ export const UI = (defaultLang = "es") => {
}, },
}); });
})); }));
}; };
/** ALERT */ /** ALERT */
ui.Alert = (props, children) => { export const Alert = (props, children) => {
const { type = "info", soft = true, ...rest } = props; const { type = "info", soft = true, ...rest } = props;
const icons = { const icons = {
info: iconInfo, info: iconInfo,
@@ -1014,10 +946,10 @@ export const UI = (defaultLang = "es") => {
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,
], ],
); );
}; };
/** TIMELINE */ /** TIMELINE */
ui.Timeline = (props) => { export const Timeline = (props) => {
const { items = [], vertical = true, compact = false, ...rest } = props; const { items = [], vertical = true, compact = false, ...rest } = props;
const icons = { const icons = {
@@ -1061,10 +993,10 @@ export const UI = (defaultLang = "es") => {
), ),
], ],
); );
}; };
/** FAB */ /** FAB */
ui.Fab = (props) => { export const 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(
@@ -1103,10 +1035,10 @@ export const UI = (defaultLang = "es") => {
), ),
], ],
); );
}; };
/** TOAST */ /** TOAST */
ui.Toast = (message, type = "alert-success", duration = 3500) => { export const 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", {
@@ -1144,7 +1076,7 @@ export const UI = (defaultLang = "es") => {
}, },
[ [
$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 }, "✕"), Button({ class: "btn-xs btn-circle btn-ghost", onclick: close }, "✕"),
], ],
); );
@@ -1159,20 +1091,32 @@ export const UI = (defaultLang = "es") => {
} }
return close; return close;
}; };
/** LOADING */ /** LOADING */
ui.Loading = (props) => { export const 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" }),
]), ]),
); );
};
// --- EXPORT UI FUNCTION ---
export const UI = (defaultLang = "es") => {
// Set initial locale
if (defaultLang) currentLocale(defaultLang);
// Create UI object with all components
const ui = {
SetLocale, tt, Button, Input, Select, Autocomplete, Datepicker, Colorpicker,
CheckBox, Radio, Range, Modal, Grid, Dropdown, Accordion, Tabs, Badge,
Tooltip, Navbar, Menu, Drawer, Fieldset, List, Stack, Stat, Swap, Indicator,
Rating, Alert, Timeline, Fab, Toast, Loading
}; };
ui.tt = tt; // Inject all components into window
Object.keys(ui).forEach((key) => { Object.keys(ui).forEach((key) => {
$[key] = ui[key];
Object.defineProperty(window, key, { Object.defineProperty(window, key, {
value: ui[key], value: ui[key],
writable: false, writable: false,