use_hovered
use_hovered tells a component whether the mouse is over the element it returns,
as CSS's :hover does,
so it can highlight itself under the pointer:
@component
def menu_item(label: str) -> Text:
hovered = use_hovered()
return Text(
content=f"{'>' if hovered.border else ' '} {label}",
style=pad_right(1) | (text_bg("sky", 800) if hovered.border else text_color("slate", 300)),
)
@component
def menu() -> Div:
return Div(
style=col | border | border_lightrounded | fit_content_width,
children=tuple(menu_item(label) for label in ("New file", "Open...", "Save", "Save as...", "Quit")),
)
The highlight follows the pointer down the menu, and goes away when the pointer leaves it:
Which box the mouse is in
Hovered reports each of the element's boxes,
from its content box out to its margin box, so a component can tell the mouse over its border from the mouse over its content.
Each box holds the ones inside it, so the mouse in the content box is in all four:
@component
def boxes() -> Div:
hovered = use_hovered()
return Div(
style=col
| margin(1)
| margin_color("slate", 800)
| border
| border_lightrounded
| (border_color("amber", 400) if hovered.border else None)
| pad(1)
| padding_color("slate", 700)
| content_color("slate", 900)
| fit_content_width,
children=tuple(
Text(
content=f"{name:<7} {'yes' if is_hovered else 'no'}",
style=text_color("emerald" if is_hovered else "slate", 400),
)
for name, is_hovered in (
("content", hovered.content),
("padding", hovered.padding),
("border", hovered.border),
("margin", hovered.margin),
)
),
)
Here the pointer crosses the margin, the border and the padding into the content, then leaves through the bottom:
Only the parts of the element that are painted count: the mouse over a part of it that an ancestor clips away, such as a row scrolled out of a scroll container, is outside all four boxes (see Clipping and the mouse).
When it renders again
use_hovered is built on use_mouse and use_rects,
so a component that calls it renders again on every move of the mouse, wherever it is on the screen,
and whenever its boxes move.
It checks the mouse against the boxes as the last layout placed them,
and renders again before a frame that moves them is painted, as use_rects does,
so it checks against where the boxes are drawn.
API
counterweight.hooks.use_hovered
use_hovered() -> Hovered
counterweight.hooks.Hovered
dataclass
Which of an element's boxes the mouse is over, as use_hovered returns it.
Each box holds the ones inside it, so the mouse over the content box is over all four.
padding
instance-attribute
padding: bool
Whether the mouse is over the padding box: the content and the padding around it.
border
instance-attribute
border: bool
Whether the mouse is over the border box: the padding box and the border around it.
margin
instance-attribute
margin: bool
Whether the mouse is over the margin box: the border box and the margin around it.