///|
const FormFieldLayoutStyle : String = "display:flex;width:100%;flex-direction:column;gap:0.5rem"
///|
const FormFieldInvalidStyle : String = "color:var(--rui-destructive,oklch(0.577 0.245 27.325))"
///|
pub fn[C : @html.IsChildren] form(
action? : String,
name? : String,
on_submit? : @cmd.Cmd,
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
@html.form(
action?,
name?,
on_submit?,
id?,
class?,
title?,
attrs=ui_attrs(attrs).data_set("slot", "form"),
style=ui_styles(
[UiBoxSizing, UiFontSans, "display:flex;flex-direction:column;gap:1.5rem"],
style,
),
children,
)
}
///|
/// Adapt caller-owned field state into one semantic Rabbita form group.
///
/// This is not React Hook Form's context-backed `FormField`: it does not
/// register, validate, or retain a value. Pass the field name and validity from
/// the application's TEA model, and keep native `id`, `for`, and description
/// relationships explicit on the composed controls.
pub fn[C : @html.IsChildren] form_field(
name~ : String,
invalid? : Bool = false,
required? : Bool = false,
describedby? : String,
errormessage? : String,
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
let field_attrs = ui_attrs(attrs)
.role("group")
.data_set("slot", "form-field")
.data_set("name", name)
.data_set("invalid", ui_bool(invalid))
.data_set("required", ui_bool(required))
if invalid {
ignore(field_attrs.aria_invalid("true"))
}
if required {
ignore(field_attrs.aria_required("true"))
}
if describedby is Some(description_id) {
ignore(field_attrs.aria_describedby(description_id))
}
if invalid && errormessage is Some(message_id) {
ignore(field_attrs.aria_errormessage(message_id))
}
@html.div(
id?,
class?,
title?,
attrs=field_attrs,
style=ui_styles(
[FormFieldLayoutStyle, if invalid { FormFieldInvalidStyle } else { "" }],
style,
),
children,
)
}
///|
pub fn[C : @html.IsChildren] form_item(
invalid? : Bool = false,
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
let item_attrs = ui_attrs(attrs)
.role("group")
.data_set("slot", "form-item")
.data_set("invalid", ui_bool(invalid))
if invalid {
ignore(item_attrs.aria_invalid("true"))
}
@html.div(
id?,
class?,
title?,
attrs=item_attrs,
style=ui_styles(
[FormFieldLayoutStyle, if invalid { FormFieldInvalidStyle } else { "" }],
style,
),
children,
)
}
///|
pub fn[C : @html.IsChildren] form_label(
for_? : String,
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
@html.label(
for_?,
id?,
class?,
title?,
attrs=ui_attrs(attrs).data_set("slot", "form-label"),
style=ui_styles(
[
"display:flex;width:fit-content;align-items:center;gap:0.5rem;font-size:0.875rem;line-height:1.375;font-weight:500",
],
style,
),
children,
)
}
///|
pub fn[C : @html.IsChildren] form_control(
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
@html.div(
id?,
class?,
title?,
attrs=ui_attrs(attrs).data_set("slot", "form-control"),
style=ui_styles(["min-width:0"], style),
children,
)
}
///|
pub fn[C : @html.IsChildren] form_description(
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
@html.p(
id?,
class?,
title?,
attrs=ui_attrs(attrs).data_set("slot", "form-description"),
style=ui_styles(
[
"margin:0;color:var(--rui-muted-foreground,oklch(0.556 0 0));font-size:0.875rem;line-height:1.5;font-weight:400",
],
style,
),
children,
)
}
///|
pub fn[C : @html.IsChildren] form_message(
id? : String,
class? : String,
title? : String,
attrs? : @html.Attrs,
style? : Array[String] = [],
children : C,
) -> @html.Html {
@html.div(
id?,
class?,
title?,
attrs=ui_attrs(attrs).role("alert").data_set("slot", "form-message"),
style=ui_styles(
[
"color:var(--rui-destructive,oklch(0.577 0.245 27.325));font-size:0.875rem;line-height:1.25rem;font-weight:400",
],
style,
),
children,
)
}