simplify components
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s

This commit is contained in:
2026-04-20 13:12:13 +02:00
parent dfd358c950
commit 82fc96fac4
15 changed files with 164 additions and 172 deletions

34
dist/sigpro-ui.esm.js vendored
View File

@@ -727,17 +727,12 @@ __export(exports_Button, {
Button: () => Button Button: () => Button
}); });
var Button = (props, children) => { var Button = (props, children) => {
const { class: className, loading, icon, ...rest } = props; const { class: className, ...rest } = props;
const iconEl = getIcon(icon);
return S("button", { return S("button", {
...rest, ...rest,
class: ui("btn", className), class: ui("btn", className),
disabled: () => val2(loading) || val2(props.disabled) disabled: () => val2(props.disabled)
}, () => [ }, () => children);
val2(loading) && S("span", { class: "loading loading-spinner" }),
iconEl,
children
].filter(Boolean));
}; };
// src/components/Checkbox.js // src/components/Checkbox.js
@@ -1282,6 +1277,17 @@ var Fileinput = (props) => {
]); ]);
}; };
// src/components/Icon.js
var exports_Icon = {};
__export(exports_Icon, {
Icon: () => Icon
});
var Icon = (iconClass) => {
if (!iconClass)
return null;
return S("span", { class: iconClass });
};
// src/components/Indicator.js // src/components/Indicator.js
var exports_Indicator = {}; var exports_Indicator = {};
__export(exports_Indicator, { __export(exports_Indicator, {
@@ -1526,6 +1532,16 @@ var Select = (props) => {
]); ]);
}; };
// src/components/Spinner.js
var exports_Spinner = {};
__export(exports_Spinner, {
Spinner: () => Spinner
});
var Spinner = (props) => {
const { value, ...rest } = props;
return If(() => val2(value), () => S("span", { class: "loading loading-spinner", ...rest }));
};
// src/components/Stack.js // src/components/Stack.js
var exports_Stack = {}; var exports_Stack = {};
__export(exports_Stack, { __export(exports_Stack, {
@@ -1827,6 +1843,7 @@ var Components = {
...exports_Fab, ...exports_Fab,
...exports_Fieldset, ...exports_Fieldset,
...exports_Fileinput, ...exports_Fileinput,
...exports_Icon,
...exports_Indicator, ...exports_Indicator,
...exports_Input, ...exports_Input,
...exports_Label, ...exports_Label,
@@ -1838,6 +1855,7 @@ var Components = {
...exports_Range, ...exports_Range,
...exports_Rating, ...exports_Rating,
...exports_Select, ...exports_Select,
...exports_Spinner,
...exports_Stack, ...exports_Stack,
...exports_Stat, ...exports_Stat,
...exports_Swap, ...exports_Swap,

File diff suppressed because one or more lines are too long

34
dist/sigpro-ui.js vendored
View File

@@ -758,17 +758,12 @@
Button: () => Button Button: () => Button
}); });
var Button = (props, children) => { var Button = (props, children) => {
const { class: className, loading, icon, ...rest } = props; const { class: className, ...rest } = props;
const iconEl = getIcon(icon);
return S("button", { return S("button", {
...rest, ...rest,
class: ui("btn", className), class: ui("btn", className),
disabled: () => val2(loading) || val2(props.disabled) disabled: () => val2(props.disabled)
}, () => [ }, () => children);
val2(loading) && S("span", { class: "loading loading-spinner" }),
iconEl,
children
].filter(Boolean));
}; };
// src/components/Checkbox.js // src/components/Checkbox.js
@@ -1313,6 +1308,17 @@
]); ]);
}; };
// src/components/Icon.js
var exports_Icon = {};
__export(exports_Icon, {
Icon: () => Icon
});
var Icon = (iconClass) => {
if (!iconClass)
return null;
return S("span", { class: iconClass });
};
// src/components/Indicator.js // src/components/Indicator.js
var exports_Indicator = {}; var exports_Indicator = {};
__export(exports_Indicator, { __export(exports_Indicator, {
@@ -1557,6 +1563,16 @@
]); ]);
}; };
// src/components/Spinner.js
var exports_Spinner = {};
__export(exports_Spinner, {
Spinner: () => Spinner
});
var Spinner = (props) => {
const { value, ...rest } = props;
return If(() => val2(value), () => S("span", { class: "loading loading-spinner", ...rest }));
};
// src/components/Stack.js // src/components/Stack.js
var exports_Stack = {}; var exports_Stack = {};
__export(exports_Stack, { __export(exports_Stack, {
@@ -1858,6 +1874,7 @@
...exports_Fab, ...exports_Fab,
...exports_Fieldset, ...exports_Fieldset,
...exports_Fileinput, ...exports_Fileinput,
...exports_Icon,
...exports_Indicator, ...exports_Indicator,
...exports_Input, ...exports_Input,
...exports_Label, ...exports_Label,
@@ -1869,6 +1886,7 @@
...exports_Range, ...exports_Range,
...exports_Rating, ...exports_Rating,
...exports_Select, ...exports_Select,
...exports_Spinner,
...exports_Stack, ...exports_Stack,
...exports_Stat, ...exports_Stat,
...exports_Swap, ...exports_Swap,

File diff suppressed because one or more lines are too long

25
dist/sigpro.css vendored
View File

@@ -4163,6 +4163,19 @@
mask-size: 100% 100%; mask-size: 100% 100%;
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 9h16M4 15h16M10 3L8 21m8-18l-2 18'/%3E%3C/svg%3E"); --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 9h16M4 15h16M10 3L8 21m8-18l-2 18'/%3E%3C/svg%3E");
} }
.icon-\[lucide--heart\] {
display: inline-block;
width: 1em;
height: 1em;
background-color: currentColor;
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 9.5a5.5 5.5 0 0 1 9.591-3.676a.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5'/%3E%3C/svg%3E");
}
.icon-\[lucide--info\] { .icon-\[lucide--info\] {
display: inline-block; display: inline-block;
width: 1em; width: 1em;
@@ -6926,18 +6939,6 @@
color: oklch(28% 0.01 260); color: oklch(28% 0.01 260);
font-size: 1.1rem; font-size: 1.1rem;
} }
.collapse .collapse-content {
transform: scaleY(0);
transform-origin: top;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
height: 0;
opacity: 0;
}
.collapse:has(input:checked) .collapse-content {
transform: scaleY(1);
height: auto;
opacity: 1;
}
.tab-content-inner { .tab-content-inner {
animation: tabFadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1); animation: tabFadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transform-origin: top; transform-origin: top;

2
dist/sigpro.min.css vendored

File diff suppressed because one or more lines are too long

View File

@@ -17,13 +17,13 @@
## Classes (daisyUI) ## Classes (daisyUI)
| Category | Keywords | Description | | Category | Keywords | Description |
| :--- | :--- | :--- | | :------- | :--------------------------------------------------------------------------------------------------------------- | :-------------------- |
| Color | `btn-primary`, `btn-secondary`, `btn-accent`, `btn-ghost`, `btn-info`, `btn-success`, `btn-warning`, `btn-error` | Visual color variants | | Color | `btn-primary`, `btn-secondary`, `btn-accent`, `btn-ghost`, `btn-info`, `btn-success`, `btn-warning`, `btn-error` | Visual color variants |
| Size | `btn-xs`, `btn-sm`, `btn-md`, `btn-lg`, `btn-xl` | Button scale | | Size | `btn-xs`, `btn-sm`, `btn-md`, `btn-lg`, `btn-xl` | Button scale |
| Style | `btn-outline`, `btn-soft`, `btn-dash`, `btn-link` | Visual style variants | | Style | `btn-outline`, `btn-soft`, `btn-dash`, `btn-link` | Visual style variants |
| Shape | `btn-circle`, `btn-square`, `btn-wide`, `btn-block` | Button shape | | Shape | `btn-circle`, `btn-square`, `btn-wide`, `btn-block` | Button shape |
| State | `btn-active`, `btn-disabled` | Forced visual states | | State | `btn-active`, `btn-disabled` | Forced visual states |
> SigProUI supports styling via daisyUI independently or combined with the `ui` prop. > SigProUI supports styling via daisyUI independently or combined with the `ui` prop.
> For further details, check the [daisyUI Button Documentation](https://daisyui.com/components/button) Full reference for CSS classes. > For further details, check the [daisyUI Button Documentation](https://daisyui.com/components/button) Full reference for CSS classes.
@@ -31,7 +31,7 @@
### Example ### Example
```javascript ```javascript
Button({ class: "btn-primary btn-lg btn-circle gap-4"}, "Click Me"); Button({ class: "btn-primary btn-lg btn-circle gap-4" }, "Click Me");
// Applies: primary color, large size, circular shape // Applies: primary color, large size, circular shape
// class is any css class from pure css or favorite framework // class is any css class from pure css or favorite framework
``` ```
@@ -62,14 +62,14 @@ const LoadingDemo = () => {
return Button( return Button(
{ {
class: "btn-success", class: "btn-success",
loading: isSaving, disabled: isSaving,
onclick: async () => { onclick: async () => {
isSaving(true); isSaving(true);
await new Promise((resolve) => setTimeout(resolve, 2000)); await new Promise((resolve) => setTimeout(resolve, 2000));
isSaving(false); isSaving(false);
}, },
}, },
"Save Changes", [Spinner({ value: isSaving }), "Save Changes"],
); );
}; };
Mount(LoadingDemo, "#demo-loading"); Mount(LoadingDemo, "#demo-loading");
@@ -81,13 +81,9 @@ Mount(LoadingDemo, "#demo-loading");
```javascript ```javascript
const IconDemo = () => { const IconDemo = () => {
return Button( return Div({ class: "flex flex-wrap gap-2 justify-center" }, [
{ Button({ class: "btn-primary" }, [Icon("icon-[lucide--x]"), "Favorite"]),
class: "btn-primary", ]);
icon: "⭐",
},
"Favorite",
);
}; };
Mount(IconDemo, "#demo-icon"); Mount(IconDemo, "#demo-icon");
``` ```
@@ -112,7 +108,10 @@ Mount(BadgeDemo, "#demo-badge");
```javascript ```javascript
const TooltipDemo = () => { const TooltipDemo = () => {
return Tooltip({ tip: "Delete item" }, Button({ class: "btn-ghost" }, "Delete")); return Tooltip(
{ tip: "Delete item" },
Button({ class: "btn-ghost" }, "Delete"),
);
}; };
Mount(TooltipDemo, "#demo-tooltip"); Mount(TooltipDemo, "#demo-tooltip");
``` ```
@@ -131,11 +130,10 @@ const CombinedDemo = () => {
Button( Button(
{ {
class: "btn-primary btn-lg", class: "btn-primary btn-lg",
icon: "👍",
onclick: () => count(count() + 1), onclick: () => count(count() + 1),
}, },
"Like", ["👍", "Like", Icon("icon-[lucide--heart]")],
) ),
), ),
); );
}; };
@@ -154,6 +152,7 @@ const VariantsDemo = () => {
Button({ class: "btn-accent" }, "Accent"), Button({ class: "btn-accent" }, "Accent"),
Button({ class: "btn-ghost" }, "Ghost"), Button({ class: "btn-ghost" }, "Ghost"),
Button({ class: "btn-outline" }, "Outline"), Button({ class: "btn-outline" }, "Outline"),
Button({ class: "btn-disabled" }, "Disabled"),
]); ]);
}; };
Mount(VariantsDemo, "#demo-variants"); Mount(VariantsDemo, "#demo-variants");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -11,6 +11,7 @@ import * as DropdownModule from './src/components/Dropdown.js';
import * as FabModule from './src/components/Fab.js'; import * as FabModule from './src/components/Fab.js';
import * as FieldsetModule from './src/components/Fieldset.js'; import * as FieldsetModule from './src/components/Fieldset.js';
import * as FileinputModule from './src/components/Fileinput.js'; import * as FileinputModule from './src/components/Fileinput.js';
import * as IconModule from './src/components/Icon.js';
import * as IndicatorModule from './src/components/Indicator.js'; import * as IndicatorModule from './src/components/Indicator.js';
import * as InputModule from './src/components/Input.js'; import * as InputModule from './src/components/Input.js';
import * as LabelModule from './src/components/Label.js'; import * as LabelModule from './src/components/Label.js';
@@ -22,6 +23,7 @@ import * as RadioModule from './src/components/Radio.js';
import * as RangeModule from './src/components/Range.js'; import * as RangeModule from './src/components/Range.js';
import * as RatingModule from './src/components/Rating.js'; import * as RatingModule from './src/components/Rating.js';
import * as SelectModule from './src/components/Select.js'; import * as SelectModule from './src/components/Select.js';
import * as SpinnerModule from './src/components/Spinner.js';
import * as StackModule from './src/components/Stack.js'; import * as StackModule from './src/components/Stack.js';
import * as StatModule from './src/components/Stat.js'; import * as StatModule from './src/components/Stat.js';
import * as SwapModule from './src/components/Swap.js'; import * as SwapModule from './src/components/Swap.js';
@@ -46,6 +48,7 @@ export const Components = {
...FabModule, ...FabModule,
...FieldsetModule, ...FieldsetModule,
...FileinputModule, ...FileinputModule,
...IconModule,
...IndicatorModule, ...IndicatorModule,
...InputModule, ...InputModule,
...LabelModule, ...LabelModule,
@@ -57,6 +60,7 @@ export const Components = {
...RangeModule, ...RangeModule,
...RatingModule, ...RatingModule,
...SelectModule, ...SelectModule,
...SpinnerModule,
...StackModule, ...StackModule,
...StatModule, ...StatModule,
...SwapModule, ...SwapModule,

View File

@@ -14,17 +14,11 @@ import { ui, val, getIcon } from "../utils.js";
* - btn-active, btn-disabled * - btn-active, btn-disabled
*/ */
export const Button = (props, children) => { export const Button = (props, children) => {
const { class: className, loading, icon, ...rest } = props; const { class: className, ...rest } = props;
const iconEl = getIcon(icon);
return Tag("button", { return Tag("button", {
...rest, ...rest,
class: ui('btn', className), class: ui('btn', className),
disabled: () => val(loading) || val(props.disabled), disabled: () => val(props.disabled),
}, () => [ }, () => children);
val(loading) && Tag("span", { class: "loading loading-spinner" }),
iconEl,
children
].filter(Boolean));
}; };

View File

@@ -1,45 +1,52 @@
import { $$ } from "sigpro"; import { $$, Tag, isFunc } from "sigpro";
export const Fetch = ({ url, options = {}, fallback = "Cargando..." }, { children }) => {
const state = $$({ data: null, loading: true, error: null });
let controller = null;
const run = async () => { const _cache = new Map();
if (controller) controller.abort();
controller = new AbortController();
state.loading = true;
state.error = null;
try { const getStore = (key) => {
const targetUrl = isFunc(url) ? url() : url; if (!_cache.has(key)) {
const fetchOpts = { _cache.set(key, $$({ data: null, loading: false, error: null }));
...(isFunc(options) ? options() : options), }
signal: controller.signal return _cache.get(key);
}; };
const res = await fetch(targetUrl, fetchOpts); export const Request = async (key, url, opts = {}) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`); const store = getStore(key);
const { body, ...rest } = opts;
const contentType = res.headers.get("content-type"); store.loading = true;
state.data = contentType?.includes("application/json") store.error = null;
? await res.json()
: await res.text();
} catch (err) {
if (err.name !== 'AbortError') state.error = err.message;
} finally {
state.loading = false;
}
};
if (isFunc(url)) Watch(url, run); try {
else run(); const config = {
method: rest.method || 'GET',
headers: { 'Content-Type': 'application/json', ...rest.headers },
...rest
};
onUnmount(() => controller?.abort()); if (body) config.body = typeof body === 'object' ? JSON.stringify(body) : body;
return Tag("div", { class: "sigpro-fetch" }, [ const res = await fetch(url, config);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const result = await res.json();
store.data = result;
return result;
} catch (err) {
store.error = err.message;
throw err;
} finally {
store.loading = false;
}
};
export const Response = ({ name, loading, error }, { children }) => {
const store = getStore(name);
return Tag("div", { style: "display:contents" }, [
() => { () => {
if (state.loading) return fallback; if (store.loading) return loading || "Cargando...";
if (state.error) return Tag("span", { style: "color:red" }, state.error); if (store.error) return isFunc(error) ? error(store.error) : Tag("p", {}, store.error);
if (state.data) return isFunc(children[0]) ? children[0](state.data) : children; if (store.data) return isFunc(children[0]) ? children[0](store.data) : children;
return null; return null;
} }
]); ]);

View File

@@ -1,53 +0,0 @@
import { $$, Tag, isFunc } from "sigpro";
const _cache = new Map();
const getStore = (key) => {
if (!_cache.has(key)) {
_cache.set(key, $$({ data: null, loading: false, error: null }));
}
return _cache.get(key);
};
export const Request = async (key, url, opts = {}) => {
const store = getStore(key);
const { body, ...rest } = opts;
store.loading = true;
store.error = null;
try {
const config = {
method: rest.method || 'GET',
headers: { 'Content-Type': 'application/json', ...rest.headers },
...rest
};
if (body) config.body = typeof body === 'object' ? JSON.stringify(body) : body;
const res = await fetch(url, config);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const result = await res.json();
store.data = result;
return result;
} catch (err) {
store.error = err.message;
throw err;
} finally {
store.loading = false;
}
};
export const Response = ({ name, loading, error }, { children }) => {
const store = getStore(name);
return Tag("div", { style: "display:contents" }, [
() => {
if (store.loading) return loading || "Cargando...";
if (store.error) return isFunc(error) ? error(store.error) : Tag("p", {}, store.error);
if (store.data) return isFunc(children[0]) ? children[0](store.data) : children;
return null;
}
]);
};

11
src/components/Spinner.js Normal file
View File

@@ -0,0 +1,11 @@
// components/Spinner.js
import { Tag } from "sigpro";
import { val } from "../utils.js";
export const Spinner = (props) => {
const { value, ...rest } = props;
return If(
() => val(value),
() => Tag("span", { class: "loading loading-spinner", ...rest })
);
};

View File

@@ -2,8 +2,6 @@
@plugin "daisyui"; @plugin "daisyui";
@plugin "@iconify/tailwind4"; @plugin "@iconify/tailwind4";
/* join join-vertical lg:join-horizontal divider divider-horizontal validator validator-hint glass */
@plugin "daisyui/theme" { @plugin "daisyui/theme" {
name: "light"; name: "light";
default: true; default: true;
@@ -99,6 +97,7 @@
} }
} }
.floating-label span { .floating-label span {
color: oklch(30% 0.01 260); /* Gris más oscuro (30% es más oscuro que 45%) */ color: oklch(30% 0.01 260); /* Gris más oscuro (30% es más oscuro que 45%) */
font-size: 1.1rem; /* text-base: más grande que 0.875rem */ font-size: 1.1rem; /* text-base: más grande que 0.875rem */
@@ -115,18 +114,6 @@
font-size: 1.1rem; /* Mantiene el mismo tamaño */ font-size: 1.1rem; /* Mantiene el mismo tamaño */
} }
.collapse .collapse-content {
transform: scaleY(0);
transform-origin: top;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
height: 0;
opacity: 0;
}
.collapse:has(input:checked) .collapse-content {
transform: scaleY(1);
height: auto;
opacity: 1;
}
.tab-content-inner { .tab-content-inner {
animation: tabFadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1); animation: tabFadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@@ -144,8 +131,11 @@
} }
} }
/* sigpro-ui daisyUI classes - extracted from components */ /* sigpro-ui daisyUI classes - extracted from components */
/* join join-vertical lg:join-horizontal divider divider-horizontal validator validator-hint glass */
/* Accordion */ /* Accordion */
/* .input, .input-bordered, .input-ghost, .input-primary, .input-secondary, .input-accent, .input-info, .input-success, .input-warning, .input-error, .input-xs, .input-sm, .input-md, .input-lg, .floating-label, */ /* .input, .input-bordered, .input-ghost, .input-primary, .input-secondary, .input-accent, .input-info, .input-success, .input-warning, .input-error, .input-xs, .input-sm, .input-md, .input-lg, .floating-label, */
@@ -354,3 +344,6 @@
/* Misc */ /* Misc */
/* .active, .hr, .label, .label-text, */ /* .active, .hr, .label, .label-text, */
/* Icons */
/* .icon-[lucide--heart] */