1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2026 FernTech
//! Tier-3 style protocol for `StandardListItem` / `StandardTreeItem`.
//! See `docs/styling-system.md`.
use std::rc::Rc;
use teksilo_tokens::TextRole;
use crate::build_context::BuildContext;
use crate::signal::Signal;
use crate::widget_id::WidgetId;
#[derive(Clone, Debug)]
pub struct StandardItemStyleConfig {
/// Pre-built row content — typically an HStack of `[checkbox?]
/// [leading?] [center?] [label / VStack { label, subtitle row }]
/// [Spacer] [trailing?]` composed by the host
/// `StandardListItem` / `StandardTreeItem`. The style is
/// responsible for the chrome (selection background, corner
/// radius, padding) but not for row-internal layout — the
/// per-slot composition is StandardItem-specific (subtitle has
/// its own sub-row, the checkbox carries `labels_hidden` AT
/// metadata, etc.) and would force every custom style to
/// reimplement it.
pub content: WidgetId,
pub is_selected: Signal<bool>,
pub is_hovered: Signal<bool>,
pub is_pressed: Signal<bool>,
pub is_focused: Signal<bool>,
/// Input-modality "focus-visible": `true` after keyboard input. A focus ring
/// should render only when this and `is_focused` are both true, so a mouse
/// click selects without a ring while keyboard navigation reveals one.
pub is_focus_visible: Signal<bool>,
pub is_disabled: Signal<bool>,
/// Whether the host window is currently active (`focused AND not occluded`).
/// Composed with `is_focused` so a selected row shows the vivid `Selected`
/// surface only while the view holds keyboard focus **and** the window is
/// active; otherwise it falls back to the muted `SelectedInactive` — the
/// same desaturation a view-focus loss produces (macOS "unemphasized"
/// selection serves both states). Populated from
/// `BuildContext::window_active_signal`.
pub is_window_active: Signal<bool>,
}
pub trait StandardItemStyle: 'static {
fn make_body(&self, cfg: &StandardItemStyleConfig, ctx: &mut BuildContext) -> WidgetId;
/// The text role a row's label takes while the row is **emphasised**
/// — selected, with its view focused and its window active. `None`
/// (the default) keeps the row's own mapping, `TextRole::Primary`.
///
/// The row builds its label before a style ever sees it, so a style
/// that fills the selection with a saturated colour cannot recolour
/// the text on top of it. Design languages whose selected row is a
/// solid accent fill with a light label — macOS's
/// `alternateSelectedControlTextColor` is the canonical case — return
/// [`TextRole::OnAccent`] here; ones whose selection is a pale wash
/// (IntUI, Fluent) leave it `None` and the label keeps its contrast
/// against the wash.
///
/// Same shape as
/// [`ButtonStyle::label_text_role`](crate::styles::ButtonStyle::label_text_role),
/// and defaulted for the same reason: an existing style needs no
/// change.
fn selected_label_role(&self) -> Option<TextRole> {
None
}
}
pub type SharedStandardItemStyle = Rc<dyn StandardItemStyle>;