Include label in Input

This commit is contained in:
2026-04-06 22:22:11 +02:00
parent ebc4dc2d3b
commit c08f001a80
46 changed files with 219 additions and 17247 deletions

View File

@@ -1,5 +1,4 @@
// components/Checkbox.js
// import { Tag } from "../sigpro.js";
import { val, ui } from "../core/utils.js";
/**
@@ -14,7 +13,7 @@ import { val, ui } from "../core/utils.js";
* - label, label-text, cursor-pointer
*/
export const Checkbox = (props) => {
const { class: className, value, tooltip, toggle, label, ...rest } = props;
const { class: className, value, toggle, label, ...rest } = props;
const checkEl = Tag("input", {
...rest,
@@ -23,10 +22,8 @@ export const Checkbox = (props) => {
checked: value
});
const layout = Tag("label", { class: "label cursor-pointer justify-start gap-3" }, [
return Tag("label", { class: "label cursor-pointer justify-start gap-3" }, [
checkEl,
label ? Tag("span", { class: "label-text" }, label) : null,
]);
return tooltip ? Tag("div", { class: "tooltip", "data-tip": tooltip }, layout) : layout;
};

View File

@@ -1,15 +1,15 @@
// components/Input.js
// import { $, Tag, Watch } from "../sigpro.js";
import { val, ui, getIcon } from "../core/utils.js";
/**
* Input component - Solo el input con ícono integrado a la izquierda
* Input component - Input con ícono integrado, toggle password, validación y floating label opcional
*
* daisyUI classes used:
* - 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
* - btn, btn-ghost, btn-xs, btn-sm, btn-md, btn-circle, opacity-50, hover:opacity-100
* - floating-label
* - btn, btn-ghost, btn-xs, btn-sm, btn-md, btn-circle
*/
export const Input = (props) => {
const {
@@ -20,8 +20,8 @@ export const Input = (props) => {
oninput,
placeholder,
disabled,
size,
validate,
label,
...rest
} = props;
@@ -74,7 +74,7 @@ export const Input = (props) => {
const inputElement = Tag("input", {
...rest,
type: () => (isPassword ? (visible() ? "text" : "password") : type),
placeholder: placeholder || " ",
placeholder: placeholder || (label ? " " : placeholder),
class: inputClasses,
value: value,
oninput: handleInput,
@@ -82,29 +82,32 @@ export const Input = (props) => {
"aria-invalid": () => hasError() ? "true" : "false",
});
return Tag(
"div",
{ class: "relative w-full" },
() => [
inputElement,
leftIcon ? Tag("div", {
class: "absolute left-3 inset-y-0 flex items-center pointer-events-none text-base-content/60",
}, leftIcon) : null,
isPassword ? Tag("button", {
type: "button",
class: ui(
"absolute right-3 inset-y-0 flex items-center",
"btn btn-ghost btn-circle opacity-50 hover:opacity-100",
buttonSize()
),
onclick: (e) => {
e.preventDefault();
visible(!visible());
}
}, () => getPasswordIcon()) : null,
Tag("div", {
class: "text-error text-xs mt-1 px-3 absolute -bottom-5 left-0",
}, () => hasError() ? errorMsg() : null),
]
);
const inputContent = () => [
inputElement,
leftIcon ? Tag("div", {
class: "absolute left-3 inset-y-0 flex items-center pointer-events-none text-base-content/60",
}, leftIcon) : null,
isPassword ? Tag("button", {
type: "button",
class: ui("absolute right-3 inset-y-0 flex items-center", "btn btn-ghost btn-circle opacity-50 hover:opacity-100", buttonSize()),
onclick: (e) => {
e.preventDefault();
visible(!visible());
}
}, () => getPasswordIcon()) : null,
Tag("div", {
class: "text-error text-xs mt-1 px-3 absolute -bottom-5 left-0",
}, () => hasError() ? errorMsg() : null),
];
// Con floating label - añadir w-full para que ocupe todo el ancho
if (label) {
return Tag("label", { class: ui("floating-label w-full", className) }, () => [
Tag("div", { class: "relative w-full" }, inputContent),
Tag("span", {}, val(label))
]);
}
// Sin label
return Tag("div", { class: "relative w-full" }, inputContent);
};

View File

@@ -1,28 +1,18 @@
// components/Label.js
// import { $, Tag } from "../sigpro.js";
import { ui, val } from "../core/utils.js";
/**
* Label component
*
* daisyUI classes used:
* - label
* - floating-label
*/
export const Label = (props) => {
const { children, value, floating = false, error, required, class: className, ...rest } = props;
const { children, value, floating = false, class: className, ...rest } = props;
if (floating) {
return Tag("label", { class: ui("floating-label w-full", className), ...rest }, () => [
value ? Tag("span", {}, value) : null,
children,
error ? Tag("span", { class: "text-error text-xs" }, val(error)) : null,
return Tag("label", { class: ui("floating-label", className), ...rest }, () => [
typeof children === 'function' ? children() : children,
value ? Tag("span", {}, val(value)) : null
]);
}
return Tag("label", { class: ui("input w-full", className), ...rest }, () => [
value ? Tag("span", { class: "label" }, value) : null,
children,
error ? Tag("span", { class: "text-error text-xs" }, val(error)) : null,
return Tag("label", { class: ui("label", className), ...rest }, () => [
value ? Tag("span", { class: "label-text" }, val(value)) : null,
typeof children === 'function' ? children() : children
]);
};

View File

@@ -14,6 +14,6 @@ import { ui } from "../core/utils.js";
export const Tooltip = (props, children) =>
Tag("div", {
...props,
class: () => ui('tooltip', props.class),
class: () => ui('tooltip w-full', props.class),
"data-tip": props.tip,
}, children);

View File

@@ -94,3 +94,19 @@
}
}
}
.floating-label span {
color: oklch(30% 0.01 260); /* Gris más oscuro (30% es más oscuro que 45%) */
font-size: 1.2rem; /* text-base: más grande que 0.875rem */
transition: all 0.2s ease;
}
.floating-label:focus-within span {
color: oklch(25% 0.02 260); /* Aún más oscuro al enfocar */
font-size: 1.2rem; /* Mantiene el mismo tamaño */
}
.floating-label:has(input:not(:placeholder-shown)) span {
color: oklch(28% 0.01 260); /* Gris oscuro cuando tiene valor */
font-size: 1.2rem; /* Mantiene el mismo tamaño */
}