| 403 |
403 |
|
}
|
| 404 |
404 |
|
|
| 405 |
405 |
|
/// A prefixed class name.
|
| 406 |
|
- |
fn class(name: &str, opts: &Emit) -> String {
|
|
406 |
+ |
///
|
|
407 |
+ |
/// Public since 0.27.0, for the renderers that emit markup this crate does not.
|
|
408 |
+ |
/// A screen renderer writing `class="row"` has to prefix it the way the
|
|
409 |
+ |
/// stylesheet half does or a prefixed app gets rules matching everything except
|
|
410 |
+ |
/// the elements that renderer wrote, and the failure is invisible: the CSS
|
|
411 |
+ |
/// stays valid and one element is unstyled. quasi-webview carried a byte
|
|
412 |
+ |
/// identical copy of this function until it could call this one.
|
|
413 |
+ |
#[must_use]
|
|
414 |
+ |
pub fn class(name: &str, opts: &Emit) -> String {
|
| 407 |
415 |
|
format!("{}{name}", opts.class_prefix)
|
| 408 |
416 |
|
}
|
| 409 |
417 |
|
|
|
418 |
+ |
/// The class an option of a selector carries, which is what the rules key off.
|
|
419 |
+ |
///
|
|
420 |
+ |
/// Named for the option and not for the group: [`selector_rules`] styles the
|
|
421 |
+ |
/// thing that gets picked, so `Selector::Tabs` is `tab` and not `tabs`. The
|
|
422 |
+ |
/// distinction is not pedantry. quasi-webview spelled these `tabs`, `segmented`
|
|
423 |
+ |
/// and `option`, put `toggle` on the wrapping element rather than on the
|
|
424 |
+ |
/// buttons inside it, and every described selector in that renderer came out
|
|
425 |
+ |
/// with no depth, no focus ring and no chosen state, while the toggle group got
|
|
426 |
+ |
/// a bevel meant for its buttons.
|
|
427 |
+ |
///
|
|
428 |
+ |
/// The chosen option additionally carries `chosen`, the same way a latched chip
|
|
429 |
+ |
/// carries `latched`. That name is this crate's too; there is no reason for a
|
|
430 |
+ |
/// caller to spell it, and [`selector_rules`] is where it is written down.
|
|
431 |
+ |
#[must_use]
|
|
432 |
+ |
pub fn option_class(selector: Selector) -> &'static str {
|
|
433 |
+ |
match selector {
|
|
434 |
+ |
Selector::Tabs => "tab",
|
|
435 |
+ |
Selector::Segmented => "segment",
|
|
436 |
+ |
Selector::Toggle => "toggle",
|
|
437 |
+ |
}
|
|
438 |
+ |
}
|
|
439 |
+ |
|
| 410 |
440 |
|
/// The fill and edge declarations for a depth, as a rule body.
|
| 411 |
441 |
|
///
|
| 412 |
442 |
|
/// Empty for [`Depth::Flat`], which has neither and inherits what it sits on.
|
| 738 |
768 |
|
/// strip hand-writing the recess that makes its chosen tab read as forward.
|
| 739 |
769 |
|
fn selector_rules(opts: &Emit) -> String {
|
| 740 |
770 |
|
let mut css = String::new();
|
| 741 |
|
- |
for (selector, name) in [
|
| 742 |
|
- |
(Selector::Tabs, "tab"),
|
| 743 |
|
- |
(Selector::Segmented, "segment"),
|
| 744 |
|
- |
(Selector::Toggle, "toggle"),
|
| 745 |
|
- |
] {
|
| 746 |
|
- |
let c = class(name, opts);
|
|
771 |
+ |
for selector in [Selector::Tabs, Selector::Segmented, Selector::Toggle] {
|
|
772 |
+ |
let c = class(option_class(selector), opts);
|
| 747 |
773 |
|
css.push_str(&depth_rule(&c, selector.unchosen()));
|
| 748 |
774 |
|
css.push_str(&interactive_rules(&c, selector.unchosen(), opts));
|
| 749 |
775 |
|
css.push_str(&depth_rule(&format!("{c}.chosen"), selector.chosen()));
|
| 1738 |
1764 |
|
assert!(!css.contains(".badge {"));
|
| 1739 |
1765 |
|
}
|
| 1740 |
1766 |
|
|
|
1767 |
+ |
#[test]
|
|
1768 |
+ |
fn the_class_a_renderer_puts_on_an_option_is_the_one_the_rules_key_off() {
|
|
1769 |
+ |
// `option_class` is the contract a screen renderer writes markup
|
|
1770 |
+ |
// against, and the rules below are the other half of it. They come off
|
|
1771 |
+ |
// one mapping now, so this asserts the mapping is the one that reaches
|
|
1772 |
+ |
// the stylesheet rather than that two lists still agree.
|
|
1773 |
+ |
let css = stylesheet(&Emit::default());
|
|
1774 |
+ |
for selector in [Selector::Tabs, Selector::Segmented, Selector::Toggle] {
|
|
1775 |
+ |
let name = option_class(selector);
|
|
1776 |
+ |
assert!(css.contains(&format!(".{name} {{")), "{name}: {css}");
|
|
1777 |
+ |
assert!(css.contains(&format!(".{name}.chosen {{")), "{name}: {css}");
|
|
1778 |
+ |
}
|
|
1779 |
+ |
assert_eq!(option_class(Selector::Tabs), "tab");
|
|
1780 |
+ |
}
|
|
1781 |
+ |
|
| 1741 |
1782 |
|
#[test]
|
| 1742 |
1783 |
|
fn a_destructive_button_has_somewhere_for_its_tone_to_land() {
|
| 1743 |
1784 |
|
let css = component_rules(&Emit::default());
|