💄 (bootsier): Añade estilos y mejora docs de Form

This commit is contained in:
Manuel Cillero 2026-05-02 11:57:05 +02:00 committed by Manuel Cillero
parent 3ceb8892a2
commit 4b50e043e0
4 changed files with 100 additions and 15 deletions

View file

@ -1,9 +1,39 @@
//! Definiciones para crear formularios ([`Form`]). //! Definiciones para crear formularios ([`Form`]).
//!
//! # Ejemplo
//!
//! ```rust
//! use pagetop::prelude::*;
//! use pagetop_bootsier::prelude::*;
//!
//! let form_login = Form::new()
//! .with_id("login")
//! .with_action("/login")
//! .with_child(
//! form::input::Field::email()
//! .with_name("email")
//! .with_label(L10n::n("Email"))
//! .with_required(true),
//! )
//! .with_child(
//! form::input::Field::password()
//! .with_name("password")
//! .with_label(L10n::n("Password"))
//! .with_required(true),
//! )
//! .with_child(
//! form::Checkbox::check()
//! .with_name("remember")
//! .with_label(L10n::n("Remember me")),
//! )
//! .with_child(
//! Button::submit(L10n::n("Sign in"))
//! .with_color(ButtonColor::Background(Color::Primary)),
//! );
//! ```
mod props; mod props;
pub use props::Method; pub use props::{Autocomplete, AutofillField, CheckboxKind, Method};
pub use props::{Autocomplete, AutofillField};
pub use props::CheckboxKind;
mod component; mod component;
pub use component::Form; pub use component::Form;

View file

@ -16,26 +16,29 @@ use crate::theme::form;
/// ///
/// # Ejemplo /// # Ejemplo
/// ///
/// ```ignore /// ```rust
/// use pagetop::prelude::*; /// # use pagetop::prelude::*;
/// use crate::prelude::*; /// # use pagetop_bootsier::prelude::*;
/// /// let search = Form::new()
/// let form = Form::new()
/// .with_id("search") /// .with_id("search")
/// .with_action("/search") /// .with_action("/search")
/// .with_method(form::Method::Get) /// .with_method(form::Method::Get)
/// .with_classes(ClassesOp::Add, "mb-3") /// .with_child(form::Input::search().with_name("q"));
/// .with_child(Input::new().with_name("q"));
/// ``` /// ```
#[derive(AutoDefault, Clone, Debug, Getters)] #[derive(AutoDefault, Clone, Debug, Getters)]
pub struct Form { pub struct Form {
#[getters(skip)] #[getters(skip)]
id: AttrId, id: AttrId,
/// Devuelve las clases CSS del formulario.
classes: Classes, classes: Classes,
/// Devuelve la URL/ruta de destino del formulario.
action: AttrValue, action: AttrValue,
/// Devuelve el método para enviar el formulario.
method: form::Method, method: form::Method,
/// Devuelve el juego de caracteres aceptado por el formulario.
#[default(_code = "AttrValue::new(\"UTF-8\")")] #[default(_code = "AttrValue::new(\"UTF-8\")")]
charset: AttrValue, charset: AttrValue,
/// Devuelve la lista de componentes del formulario.
children: Children, children: Children,
} }
@ -107,15 +110,15 @@ impl Form {
/// Establece el juego de caracteres aceptado por el formulario. /// Establece el juego de caracteres aceptado por el formulario.
/// ///
/// Por defecto se usa `"UTF-8"`. /// Por defecto se utiliza `"UTF-8"`.
#[builder_fn] #[builder_fn]
pub fn with_charset(mut self, charset: impl AsRef<str>) -> Self { pub fn with_charset(mut self, charset: impl AsRef<str>) -> Self {
self.charset.alter_str(charset); self.charset.alter_str(charset);
self self
} }
/// Añade un nuevo componente al formulario o modifica la lista de de componentes (`children`) /// Añade un nuevo componente al formulario o modifica la lista de componentes (`children`) con
/// con una operación [`ChildOp`]. /// una operación [`ChildOp`].
#[builder_fn] #[builder_fn]
pub fn with_child(mut self, op: impl Into<ChildOp>) -> Self { pub fn with_child(mut self, op: impl Into<ChildOp>) -> Self {
self.children.alter_child(op.into()); self.children.alter_child(op.into());

View file

@ -11,9 +11,9 @@ use pagetop::prelude::*;
/// ```rust /// ```rust
/// # use pagetop::prelude::*; /// # use pagetop::prelude::*;
/// # use pagetop_bootsier::prelude::*; /// # use pagetop_bootsier::prelude::*;
/// let volumen = form::Range::new() /// let volume = form::Range::new()
/// .with_name("volume") /// .with_name("volume")
/// .with_label(L10n::n("Volumen")) /// .with_label(L10n::n("Volume"))
/// .with_min(Some(0.0)) /// .with_min(Some(0.0))
/// .with_max(Some(100.0)) /// .with_max(Some(100.0))
/// .with_step(Some(5.0)) /// .with_step(Some(5.0))

View file

@ -18,6 +18,58 @@ $enable-cssgrid: true;
--bs-text-opacity: 0.1; --bs-text-opacity: 0.1;
} }
// FORMS
// Required field indicator
.form-required {
color: var(--bs-danger);
margin: 0 0.25rem;
}
// Form fields
.form-field {
margin-bottom: 1rem;
&:last-child {
margin-bottom: 0;
}
}
// Fieldset
fieldset {
position: relative;
background-color: var(--bs-body-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
border-radius: var(--bs-border-radius);
padding: 2rem 1rem 1rem;
margin: 2rem 0 1rem;
}
fieldset > legend {
position: absolute;
top: 0;
left: 1rem;
transform: translateY(-50%);
background-color: var(--bs-body-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
border-radius: var(--bs-border-radius);
padding: 0.125rem 0.75rem;
font-size: $font-size-sm;
line-height: 1.25;
width: fit-content;
max-width: 75%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.fieldset-description {
margin-bottom: 1rem;
}
// Check buttons, gap between label and first inline check
.form-label + .form-check-inline {
margin-left: 1rem;
}
// Extending utilities // Extending utilities
$utilities: map-merge( $utilities: map-merge(
$utilities, $utilities,