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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use *;
use ;
use component_doc;
use inject_style;
use spinner_styles;
/// `Spinner` shows that work is in progress when you do not know how long it will take.
///
/// Always set `label` or provide child text so assistive tech announces the wait state. Pick a [`SpinnerSize`](orbital_base_components::SpinnerSize) to match surrounding typography. Indeterminate only — use [`ProgressBar`](crate::ProgressBar) or [`ProgressCircle`](crate::ProgressCircle) when you have a measurable completion value.
///
/// # When to use
///
/// - Inline waits inside panels, cards, or empty states
/// - Button loading states and [`Backdrop`](crate::Backdrop) overlays during async work
///
/// Prefer [`ProgressBar`](crate::ProgressBar) for known totals. Prefer [`LoadingBar`](crate::LoadingBar) for app-wide route transitions.
///
/// # API notes
///
/// - Indeterminate only — use [`ProgressBar`](crate::ProgressBar) or [`ProgressCircle`](crate::ProgressCircle) for known completion values.
/// - Size steps range from `Tiny` to `Huge` via [`SpinnerSize`](orbital_base_components::SpinnerSize).
/// - Always set `label` or provide child text for assistive technology.
///
/// # Best Practices
///
/// ## Do's
///
/// * Always provide `label` or visible child text — never ship an unlabeled spinner
/// * Match `size` to surrounding typography (`Tiny` inline, `Large` in empty states)
///
/// ## Don'ts
///
/// * Do not use for known completion percentages — bind [`ProgressBar`](crate::ProgressBar) or [`ProgressCircle`](crate::ProgressCircle)
/// * Do not use for global navigation chrome — use [`LoadingBar`](crate::LoadingBar)
///
/// # Examples
///
/// ## Default spinner
/// Indeterminate spinner for async waits when no progress percentage is known. Default medium size suits inline placement beside text or inside cards.
/// <!-- preview -->
/// ```rust
/// view! {
/// <div data-testid="spinner-preview">
/// <Spinner />
/// </div>
/// }
/// ```
///
/// ## With label
/// Always provide an accessible label describing what is loading. The label is linked via `aria-labelledby` so screen readers announce the wait state.
/// <!-- preview -->
/// ```rust
/// view! {
/// <div data-testid="spinner-labeled">
/// <Spinner label="Loading data..." />
/// </div>
/// }
/// ```
///
/// ## Large size
/// Large spinners draw attention in empty states or full-width loading panels.
/// <!-- preview -->
/// ```rust
/// use orbital_base_components::SpinnerSize;
/// view! {
/// <div data-testid="spinner-large">
/// <Spinner size=Signal::from(SpinnerSize::Large) />
/// </div>
/// }
/// ```
///
/// ## Size matrix
/// Compare size presets from tiny through huge when aligning spinners with surrounding typography.
/// <!-- preview -->
/// ```rust
/// use orbital_base_components::SpinnerSize;
/// view! {
/// <div data-testid="spinner-sizes" style="display: flex; gap: 16px; align-items: center;">
/// <div data-testid="spinner-size-tiny"><Spinner size=Signal::from(SpinnerSize::Tiny) /></div>
/// <div data-testid="spinner-size-huge"><Spinner size=Signal::from(SpinnerSize::Huge) /></div>
/// </div>
/// }
/// ```
///
/// ## Children label
/// Child text can serve as the accessible label when a separate `label` prop is not needed.
/// <!-- preview -->
/// ```rust
/// view! {
/// <div data-testid="spinner-children">
/// <Spinner>"Loading"</Spinner>
/// </div>
/// }
/// ```
///
/// ## Theme token
/// Spinner stroke colors inherit brand tokens from the Orbital theme provider.
/// <!-- preview -->
/// ```rust
/// view! {
/// <div data-testid="spinner-theme">
/// <Spinner />
/// </div>
/// }
/// ```