Skip to main content

hypersig_ui/
lib.rs

1//! Accessible components for hypersig, styled after shadcn/ui.
2//!
3//! Each component is a function or a small builder that returns an
4//! [`El`](hypersig::html::El), styled with `hypersig::style` from the tokens
5//! in [`token`]. A page adds [`global`] and [`theme`] once, and the
6//! components follow the visitor's light or dark preference.
7//!
8//! The behavior a screen reader and a keyboard depend on comes from the
9//! browser where the browser has it, and from the WAI-ARIA Authoring
10//! Practices where it does not:
11//!
12//! | Component | Built on |
13//! |---|---|
14//! | [`button`], [`submit_button`], [`icon_button`] | `<button>`, with the icon button's name required |
15//! | [`TextField`] | `<label>`, `<input>` or `<textarea>`, `aria-describedby`, `aria-invalid`, a live error |
16//! | [`NumberField`] | the same, on `<input type="number">` with typed `min`, `max`, and `step` |
17//! | [`checkbox`], [`switch`] | `<input type="checkbox">`, the switch with `role="switch"` |
18//! | [`radio_group`] | `<fieldset>`, `<legend>`, and radios that share a name |
19//! | [`select_field`] | `<label>` and `<select>`, with a `base-select` picker where supported |
20//! | [`TextField::in_form`], [`select_field_in_form`], [`radio_group_in_form`], [`checkbox_in_form`], [`switch_in_form`] | the control above bound to a field of a [`Form`](hypersig::Form), with its message tied by `aria-describedby` and `aria-invalid` |
21//! | [`Slider`] | `<input type="range">` over a drawn track and thumb |
22//! | [`Listbox`] | the listbox pattern, with roving focus |
23//! | [`Combobox`] | the combobox pattern with list autocomplete and `aria-activedescendant` |
24//! | [`Tabs`] | the tabs pattern, with roving focus |
25//! | [`Chart`] | an `<svg>` hidden from assistive technology, beside a visually hidden `<table>` of the same rows |
26//! | [`DonutChart`] | the same, with each row an arc of a ring |
27//! | [`DataTable`] | `<table>` with `<th scope="col">` and `aria-sort`, and a tri-state checkbox for selecting rows |
28//! | [`ServerTable`] | the same `<table>`, whose rows an action sends one page at a time |
29//! | [`Accordion`] | `<details>` and `<summary>` |
30//! | [`Dialog`] | `<dialog>` opened by invoker commands, centered or along an edge as a sheet |
31//! | [`NavList`], [`Breadcrumb`], [`pagination`] | `<nav>` holding a list of links, with `aria-current` on the link to the page shown |
32//! | [`Menu`] | the menu button pattern on a `popover` |
33//! | [`Tooltip`] | the tooltip pattern on a `popover="hint"` |
34//! | [`Toaster`] | a landmark region holding an `aria-live` list |
35//! | [`progress`] | `role="progressbar"` |
36//!
37//! The ids that tie a label to its control, or a tab to its panel, are
38//! derived from the signal the component is bound to. A dialog, a menu, a
39//! tooltip, and a combobox take names in a `const` handle, as a
40//! [`NodeRef`](hypersig::NodeRef) does, because the runtime or the browser
41//! finds their elements by id.
42//!
43//! ```
44//! use hypersig::{Page, Signals};
45//! use hypersig_ui::{ButtonSize, ButtonVariant, TextField, button, card, card_content};
46//! use serde::{Deserialize, Serialize};
47//!
48//! #[derive(Signals, Serialize, Deserialize)]
49//! struct Signup {
50//!     name: String,
51//! }
52//!
53//! let html = Page::new("Sign up", Signup { name: String::new() })
54//!     .global(hypersig_ui::global())
55//!     .theme(hypersig_ui::theme())
56//!     .child(
57//!         card().child(
58//!             card_content()
59//!                 .child(TextField::new("Name", Signup::name()))
60//!                 .child(button(ButtonVariant::Default, ButtonSize::Default).text("Continue")),
61//!         ),
62//!     )
63//!     .render();
64//! assert!(html.contains(r#"for="ui-name-input""#));
65//! ```
66#![doc(
67    html_logo_url = "https://imaimai17468.github.io/hypersig/icon.svg",
68    html_favicon_url = "https://imaimai17468.github.io/hypersig/icon.svg"
69)]
70
71mod accordion;
72mod alert;
73mod badge;
74mod button;
75mod card;
76mod chart;
77mod choice;
78mod combobox;
79mod dialog;
80mod donut;
81mod field;
82mod id;
83mod listbox;
84mod look;
85mod menu;
86mod navigation;
87mod number;
88mod progress;
89mod select;
90mod separator;
91mod slider;
92mod table;
93mod tabs;
94mod theme;
95mod toast;
96pub mod token;
97mod tooltip;
98
99pub use accordion::Accordion;
100pub use alert::{AlertVariant, alert, alert_description, alert_title};
101pub use badge::{BadgeVariant, badge};
102pub use button::{ButtonSize, ButtonVariant, button, button_style, icon_button, submit_button};
103pub use card::{Level, card, card_content, card_description, card_footer, card_header, card_title};
104pub use chart::Chart;
105pub use choice::{
106    checkbox, checkbox_in_form, radio_group, radio_group_in_form, switch, switch_in_form,
107};
108pub use combobox::{Combobox, ComboboxState};
109pub use dialog::{Dialog, Side, dialog_footer};
110pub use donut::DonutChart;
111pub use field::{Autocomplete, InputKind, InputMode, TextField};
112pub use listbox::Listbox;
113pub use menu::{Menu, MenuItem};
114pub use navigation::{Breadcrumb, NavList, PaginationText, pagination};
115pub use number::{NumberField, Numeric};
116pub use progress::{progress, skeleton};
117pub use select::{select_field, select_field_in_form};
118pub use separator::separator;
119pub use slider::Slider;
120pub use table::{Column, DataTable, ServerTable, SortOrder, TableState, TableText};
121pub use tabs::Tabs;
122pub use theme::{dark, global, light, theme};
123pub use toast::{Toast, ToastVariant, Toaster};
124pub use tooltip::Tooltip;