The hypersig_ui crate
Buttons, fields, pickers, tabs, dialogs, menus, tooltips, and toasts, built on the browser's native elements and following the WAI-ARIA Authoring Practices. Each returns an El, so it takes handlers and children like any other element.
The browser already gives <button>, <select>, <details>, <dialog>, and popover their behavior, and the components use it as it is.
Tabs, listbox options, and menu items move with the arrow keys, Home, and End, and a combobox keeps focus in its text field.
shadcn/ui's zinc theme, with a control's border at 3:1, secondary text at 4.5:1, and focus drawn as a solid outline.
A const handle connects the dialog with the buttons that open and close it, and the browser opens it as a modal through invoker commands.
Result
use hypersig::html::{div, p};
use hypersig::style::pattern::{stack, wrap};
use hypersig::style::value::rem;
use hypersig::{Page, Signals};
use hypersig_ui::{ButtonSize, ButtonVariant, Dialog, Side, TextField, dialog_footer};
use serde::{Deserialize, Serialize};
#[derive(Signals, Serialize, Deserialize)]
pub struct Project {
name: String,
status: String,
}
const RENAME: Dialog<Project> = Dialog::new("rename");
const DELETE: Dialog<Project> = Dialog::new("delete");
const DETAILS: Dialog<Project> = Dialog::new("details");
pub fn page() -> Page<Project> {
let name = Project::name();
let status = Project::status();
let initial = Project {
name: "hypersig".into(),
status: String::new(),
};
Page::new(
"Project",
initial,
)
.child(
div()
.css(stack(rem(1)))
.child(
div()
.css(wrap(rem(0.5)))
.child(
RENAME
.trigger(ButtonVariant::Outline, ButtonSize::Default)
.text("Rename"),
)
.child(
DETAILS
.trigger(ButtonVariant::Outline, ButtonSize::Default)
.text("Details"),
)
.child(
DELETE
.trigger(ButtonVariant::Destructive, ButtonSize::Default)
.text("Delete"),
),
)
.child(p().attr("role", "status").bind_text(status))
.child(
RENAME.dialog(
"Rename project",
"The new name shows everywhere the project appears.",
div()
.css(stack(rem(1)))
.child(TextField::new(
"Name",
name,
))
.child(
dialog_footer()
.child(
RENAME
.close(ButtonVariant::Outline, ButtonSize::Default)
.text("Cancel"),
)
.child(
RENAME
.close(ButtonVariant::Default, ButtonSize::Default)
.on_click(status.set("Renamed the project."))
.text("Save"),
),
),
),
)
.child(
DETAILS.sheet(
Side::Right,
"Project details",
"Created on March 3. Deployed 12 times.",
dialog_footer().child(
DETAILS
.close(ButtonVariant::Outline, ButtonSize::Default)
.text("Done"),
),
),
)
.child(
DELETE.alert_dialog(
"Delete this project?",
"The project and its deployments are removed. This cannot be undone.",
dialog_footer()
.child(
DELETE
.close(ButtonVariant::Outline, ButtonSize::Default)
.text("Cancel"),
)
.child(
DELETE
.close(ButtonVariant::Destructive, ButtonSize::Default)
.on_click(status.set("Deleted the project."))
.text("Delete"),
),
),
),
)
}