#[non_exhaustive]pub enum Affordance {
Hover,
Hint,
Ancillary,
Detail,
Anchored,
Overflow,
Gesture,
Haptic,
}Expand description
An affordance whose existence depends on the surface it is offered on.
Drawn from what apps already gate by hand rather than from a taxonomy. The crate’s admission rule applies and is the reason each addition has to point at call sites rather than at a category: guessing is how a description becomes a framework.
Each answers Self::available against the two axes and nothing else. An
affordance that is always available is not an affordance this module has
anything to say about, and every_member_is_an_adaptation asserts none has
snuck in.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Hover
Anything a consumer reveals on hover: a row’s action cluster, a hover toolbar, a preview popover.
The crate records hover-revealed row actions as behaviour of
a row’s controls rather than as app policy. A fingertip has no hover
state at all, so the affordance does not exist on touch, and something
else has to carry the same actions: Self::Gesture.
Hint
Chrome documenting a keyboard interaction: shortcut badges, key hints, a “press / to search” line.
Strictly this is a claim about
having a keyboard rather than about the contact patch, and Density
is the closest honest proxy the family carries. Stated rather than
hidden, because a detachable-keyboard tablet is where the proxy breaks
and a third axis is what fixing it would cost.
Ancillary
A secondary panel standing beside the primary content: a saved-views rail, a filter sidebar, an inspector.
Purely a screen-budget claim (a touchscreen laptop should keep it), so
this reads SizeClass alone.
Detail
The detail half of a list-detail split, shown alongside the list rather than navigated to.
Unavailable is not the same as absent: the detail still exists, it is
reached by navigation instead of by adjacency, and which of the two a
screen gets is what Arrangement is describing.
Anchored
Navigation or a primary action cluster pinned to a fixed screen edge instead of sitting in the flow of the page.
The reposition bucket. It exists to compensate for what a compact window cannot hold in flow, so unlike the two above it is available at the narrow end and not the wide one. That inversion is the point: an adaptation that only ever removes things describes a degraded layout rather than a different one.
Overflow
An action cluster collapsed behind one control rather than laid out inline.
The other compensating member. ColumnRoom::kept_at
already handles a table narrowing by dropping columns; this is the
same pressure on a cluster of controls, which cannot drop any of them
and folds instead.
Gesture
A direct-manipulation gesture on content: swipe-to-action, long-press to select, pull to refresh, swipe to navigate, drag to dismiss.
The density axis’s compensating member, and the answer to the question
Self::Hover asks and cannot answer. A fingertip has no hover state,
so the row actions a pointer reveals by hovering have to arrive some
other way; on both webview apps that way is a swipe.
One member for five gestures, on purpose. Apps gate all five behind
one fact about the surface, so five members would be minted from one.
If a surface ever offers swipe without long-press, splitting this is
additive and the call sites that named Gesture keep meaning what they
meant.
Haptic
Confirmation delivered through the contact patch rather than the eye: the tick as a drag crosses a threshold, the thump as a gesture fires.
A contact-patch claim, which is what makes it this module’s business despite being the one member nothing on screen shows.
The proxy breaks where the hardware has haptics and the user or the OS
has switched them off. That is neither Density nor SizeClass, and
it is stated here rather than fixed for the same reason Self::Hint
states the detachable-keyboard case: a third axis is what fixing it would
cost. This member says the surface can, never that the user wants.
Asking the platform whether haptics are enabled is the renderer’s job.
Implementations§
Source§impl Affordance
impl Affordance
Sourcepub const fn available(self, density: Density, size: SizeClass) -> bool
pub const fn available(self, density: Density, size: SizeClass) -> bool
Whether this affordance exists on a surface with the given input class and screen budget.
The whole module in one call. A renderer asks per affordance and never branches on a width.
Sourcepub const fn gained_by(self) -> Option<Density>
pub const fn gained_by(self) -> Option<Density>
Which Density this affordance belongs to, or None when it reads the
screen budget instead.
Each member declares its own direction, and
a_density_member_is_available_on_exactly_the_density_it_declares holds
the declaration to the rule. There is no module-wide one-directional
rule: see the module doc.
Exposed rather than kept private for the same reason Self::reads_density
is: it is the module’s claim about itself, and a renderer that has one
density can read it directly instead of probing Self::available twice.
Sourcepub const fn axis(self) -> AffordanceAxis
pub const fn axis(self) -> AffordanceAxis
Which of the two axes this affordance’s availability reads.
Declared per member rather than derived, so the tests can hold each
declaration against what Self::available actually does.
Sourcepub const fn reads_density(self) -> bool
pub const fn reads_density(self) -> bool
Whether this affordance’s availability reads Density at all.
Exposed rather than kept private because it is the module’s own claim about itself: exactly the members gating a contact-patch interaction say yes. A renderer with one density can skip the rest entirely.
Sourcepub const fn reads_size(self) -> bool
pub const fn reads_size(self) -> bool
Whether this affordance’s availability reads SizeClass at all.
Sourcepub const fn all() -> &'static [Self]
pub const fn all() -> &'static [Self]
Every member, in declaration order.
A slice rather than an array, so a new member changes a length and not
a type: Affordance is #[non_exhaustive] for exactly that reason.
Sourcepub const fn token(self) -> &'static str
pub const fn token(self) -> &'static str
The CSS class name an app may hang off this, without the leading dot.
Present for the same reason SizeClass::token is: a webview renderer
needs a stable name, and minting it per app is how two apps end up with
has-hover and hover-capable.