makeover-layout 0.44.2

The renderer-agnostic half of the make-family design system: what a thing IS, named as intents and relationships and never as values. Colour defers to makeover, spacing to makeover-geometry; what is left is composition.
Documentation
use crate::{State, Tone};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Act<'a> {
    /// What the control says.
    pub label: &'a str,
    /// The key that reaches it where a host has keys.
    ///
    /// The one member written for a terminal before there was one. A webview
    /// hangs it off `accesskey` or ignores it; a terminal has nothing else to
    /// offer, so this is the whole of how a control is reached there.
    pub key: Option<&'a str>,
    /// What pressing it means. [`Tone::Danger`] is the destructive one.
    pub tone: Tone,
    /// Disabled, or nothing said.
    ///
    /// [`State::Disabled`] is what changes what a renderer may do: see
    /// [`State::suppresses_interaction`], which is what says a disabled control
    /// is drawn and not reachable. A control's focus is not sayable here at
    /// all: see the crate header, "Reach, focus and the focus ring".
    pub state: Option<State>,
    /// A sentence that is always true of this control, shown rather than hunted
    /// for.
    ///
    /// Standing help, not a message and not a tooltip. Half the hosts that read
    /// this have no pointer: a hover is one spelling of it, and the shipped
    /// apps reached for that spelling only because egui and a browser both had
    /// one. What is being said is that the sentence is true, never that it is
    /// hidden until a pointer arrives.
    ///
    /// # Why it is here rather than a layer up
    ///
    /// A hint left to `quasi_router::Act` alone means each renderer draws it
    /// for itself: `makeover_tui` had no hint to read, so quasi-tui built
    /// the muted line, and quasi-immediate called `on_hover_text` outside
    /// [`crate::Act`] rather than inside it. `Field::hint` was here the whole
    /// time, so the same idea sat at two layers depending on which thing
    /// carried it, and a host that was not quasi could say it of a field and
    /// not of a control.
    ///
    /// What kept it out was price rather than doubt: this crate declares
    /// `links`, so a member here moves 25 manifests across 12 repos. That is a
    /// release's forward-fix pass, which is a cost and was being read as a
    /// barrier.
    ///
    /// # What a renderer owes it
    ///
    /// Somewhere to put it, or nothing. Dropping it is legitimate; drawing it
    /// *instead of* the label is not, and neither is drawing it in a way that
    /// takes it out of the accessible tree, which is the failure `title` alone
    /// has on a browser. Nothing may live only in a hint.
    ///
    /// `None` is a control whose label is the whole of it, which is nearly all
    /// of them.
    pub hint: Option<&'a str>,
}

impl<'a> Act<'a> {
    /// An ordinary control, reachable, with no key.
    #[must_use]
    pub const fn new(label: &'a str) -> Self {
        Self {
            label,
            key: None,
            tone: Tone::Neutral,
            state: None,
            hint: None,
        }
    }

    /// The sentence that is always true of it; see [`hint`](Self::hint).
    ///
    /// A renderer with nowhere to put it drops it, so this must never be the
    /// only place a fact appears.
    #[must_use]
    pub const fn hinted(mut self, hint: &'a str) -> Self {
        self.hint = Some(hint);
        self
    }

    /// The key that reaches it.
    #[must_use]
    pub const fn key(mut self, key: &'a str) -> Self {
        self.key = Some(key);
        self
    }

    /// What pressing it means.
    #[must_use]
    pub const fn tone(mut self, tone: Tone) -> Self {
        self.tone = tone;
        self
    }

    /// Focus, or disabled.
    #[must_use]
    pub const fn state(mut self, state: State) -> Self {
        self.state = Some(state);
        self
    }

    /// Whether the control is drawn and does not answer.
    #[must_use]
    pub fn disabled(&self) -> bool {
        self.state.is_some_and(State::suppresses_interaction)
    }
}