teksilo_core/styles/link_style.rs
1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! Tier-3 style protocol for `Link`. See `docs/styling-system.md`.
5//!
6//! The style owns the full visual: the per-state text colour (idle /
7//! hover / pressed / visited / disabled), the underline policy, the
8//! corner radius, and the focus-ring border. The `Link` widget owns
9//! only the interaction state signals and dispatches events — it
10//! passes the resolved text *string* (not a pre-built `TextWidget`)
11//! through the config so the style can build the label with its own
12//! colour binding.
13
14use std::rc::Rc;
15
16use crate::build_context::BuildContext;
17use crate::signal::{Prop, Signal};
18use crate::widget_id::WidgetId;
19
20#[derive(Clone, Debug)]
21pub struct LinkStyleConfig {
22 /// Label text as a reactive `Prop<String>`. The widget converts its
23 /// `LocalizedString` via `.into()` (a `tr!` source yields a bound,
24 /// locale-reactive prop); the style binds it to the label widget.
25 /// `teksilo-core` can't name `LocalizedString` (i18n depends on core,
26 /// not the reverse), so the i18n type is erased to `Prop<String>` here.
27 pub text: Prop<String>,
28 /// `true` while the pointer is over the link.
29 pub is_hovered: Signal<bool>,
30 /// `true` while the link is being pressed (mouse-down or Space/Enter).
31 pub is_pressed: Signal<bool>,
32 /// `true` while the link holds keyboard focus.
33 pub is_focused: Signal<bool>,
34 /// `true` if the link's target has previously been visited. The
35 /// app owns visited-tracking; default `Signal::new(false)` is
36 /// fine for links that don't represent URLs.
37 pub is_visited: Signal<bool>,
38 /// `true` when the widget is effectively disabled (this node or
39 /// any ancestor has its arena `enabled_state` resolved to false).
40 /// Reactive: re-emits when `enabled_when(..., signal)` flips.
41 pub is_disabled: Signal<bool>,
42}
43
44pub trait LinkStyle: 'static {
45 fn make_body(&self, cfg: &LinkStyleConfig, ctx: &mut BuildContext) -> WidgetId;
46}
47
48pub type SharedLinkStyle = Rc<dyn LinkStyle>;