orbital_date_pickers/shared/
picker_styles.rs1use orbital_theme::Density;
2use std::sync::OnceLock;
3use turf::inline_style_sheet_values;
4
5pub struct PickerClassNames {
6 pub layout: String,
7 pub date_field: String,
8 pub time_field: String,
9 pub datetime_field: String,
10 pub segment: String,
11 pub separator: String,
12}
13
14static PICKER_STYLES: OnceLock<(&'static str, PickerClassNames)> = OnceLock::new();
15
16fn picker_styles() -> (&'static str, PickerClassNames) {
17 let (style_sheet, _) = inline_style_sheet_values! {
18 .orb-picker-layout {
19 display: flex;
20 flex-direction: column;
21 width: fit-content;
22 }
23
24 .orb-date-range-field,
25 .orb-time-range-field,
26 .orb-datetime-range-field {
27 display: inline-flex;
28 align-items: center;
29 gap: var(--orb-space-inline-sm);
30 flex-wrap: wrap;
31 }
32
33 .orb-picker-range-field__separator {
34 color: var(--orb-color-text-secondary);
35 user-select: none;
36 flex-shrink: 0;
37 }
38
39 .orb-picker-datetime-field__row {
40 display: flex;
41 flex-direction: row;
42 flex-wrap: wrap;
43 align-items: flex-start;
44 gap: var(--orb-space-inline-md);
45 width: fit-content;
46 max-width: 100%;
47 }
48
49 .orb-picker-datetime-picker__row {
50 display: flex;
51 flex-direction: row;
52 flex-wrap: wrap;
53 align-items: flex-start;
54 gap: var(--orb-space-inline-md);
55 width: fit-content;
56 max-width: 100%;
57 }
58
59 .orb-picker-datetime-picker__row > .orbital-date-picker,
60 .orb-picker-datetime-picker__row > .orbital-time-picker {
61 width: auto;
62 }
63
64 .orb-picker-datetime-picker__row > .orbital-date-picker {
65 flex: 1 1 280px;
66 min-width: 0;
67 }
68
69 .orb-picker-datetime-picker__row > .orbital-time-picker {
70 flex: 0 1 220px;
71 min-width: 0;
72 }
73
74 .orb-picker-datetime-range-picker__row {
75 display: flex;
76 flex-direction: row;
77 flex-wrap: wrap;
78 align-items: flex-start;
79 gap: var(--orb-space-inline-md);
80 margin-top: var(--orb-space-block-md);
81 width: 100%;
82 }
83
84 .orb-picker-datetime-range-picker__row > .orb-picker-layout {
85 flex: 1 1 320px;
86 min-width: 0;
87 }
88
89 .orb-picker-layout-density-compact .orbital-calendar-item {
90 padding: 4px 6px;
91 }
92
93 .orb-picker-layout-density-compact .orbital-calendar {
94 height: 560px;
95 }
96
97 .orb-picker-layout-density-spacious .orbital-calendar-item {
98 padding: 12px 16px;
99 }
100
101 .orb-picker-layout-density-spacious .orbital-calendar {
102 height: 840px;
103 }
104
105 .orb-picker-shortcuts {
106 margin-bottom: var(--orb-space-block-sm);
107 padding-bottom: var(--orb-space-block-sm);
108 border-bottom: 1px solid var(--orb-color-border-subtle);
109 }
110 };
111
112 let class_names = PickerClassNames {
113 layout: "orb-picker-layout".to_string(),
114 date_field: "orb-date-field".to_string(),
115 time_field: "orb-time-field".to_string(),
116 datetime_field: "orb-datetime-field".to_string(),
117 segment: "orb-date-field__segment".to_string(),
118 separator: "orb-date-field__separator".to_string(),
119 };
120
121 (style_sheet, class_names)
122}
123
124pub fn picker_style_sheet() -> &'static str {
126 PICKER_STYLES.get_or_init(picker_styles).0
127}
128
129pub fn picker_class_names() -> &'static PickerClassNames {
131 &PICKER_STYLES.get_or_init(picker_styles).1
132}
133
134pub fn picker_density_class(density: Density) -> &'static str {
136 match density {
137 Density::Compact => "orb-picker-layout--density-compact",
138 Density::Default => "",
139 Density::Spacious => "orb-picker-layout--density-spacious",
140 }
141}
142
143pub fn picker_density_inner_class(density: Density) -> &'static str {
145 match density {
146 Density::Compact => "orb-picker-layout-density-compact",
147 Density::Default => "",
148 Density::Spacious => "orb-picker-layout-density-spacious",
149 }
150}
151
152pub fn datetime_picker_root_classes(density: Density) -> String {
154 format!(
155 "{} orb-picker-datetime-picker",
156 layout_root_classes(density)
157 )
158}
159
160pub fn datetime_field_row_class() -> &'static str {
162 "orb-picker-datetime-field__row"
163}
164
165pub fn datetime_picker_row_class() -> &'static str {
167 "orb-picker-datetime-picker__row"
168}
169
170pub fn datetime_range_picker_row_class() -> &'static str {
172 "orb-picker-datetime-range-picker__row"
173}
174
175pub fn layout_root_classes(density: Density) -> String {
177 let names = picker_class_names();
178 let mut parts = vec![names.layout.clone()];
179 let modifier = picker_density_class(density);
180 if !modifier.is_empty() {
181 parts.push(modifier.to_string());
182 }
183 let inner = picker_density_inner_class(density);
184 if !inner.is_empty() {
185 parts.push(inner.to_string());
186 }
187 parts.join(" ")
188}
189
190pub fn input_size_class(density: Density) -> &'static str {
192 match density {
193 Density::Compact => "orbital-input--small",
194 Density::Default => "",
195 Density::Spacious => "orbital-input--large",
196 }
197}
198
199pub fn datetime_field_root_classes(density: Density) -> String {
201 let names = picker_class_names();
202 let mut parts = vec!["orbital-input".to_string(), names.datetime_field.clone()];
203 let size = input_size_class(density);
204 if !size.is_empty() {
205 parts.push(size.to_string());
206 }
207 parts.join(" ")
208}
209
210pub fn datetime_segment_class() -> &'static str {
212 "orb-datetime-field__segment"
213}
214
215pub fn datetime_separator_class() -> &'static str {
217 "orb-datetime-field__separator"
218}
219
220pub fn field_root_classes(is_time: bool, density: Density) -> String {
222 let names = picker_class_names();
223 let field = if is_time {
224 names.time_field.clone()
225 } else {
226 names.date_field.clone()
227 };
228 let mut parts = vec!["orbital-input".to_string(), field];
229 let size = input_size_class(density);
230 if !size.is_empty() {
231 parts.push(size.to_string());
232 }
233 parts.join(" ")
234}
235
236pub fn time_segment_class() -> &'static str {
238 "orb-time-field__segment"
239}
240
241pub fn time_separator_class() -> &'static str {
242 "orb-time-field__separator"
243}
244
245pub fn time_clock_root_classes(density: Density) -> String {
247 let mut parts = vec!["orb-picker-time-clock".to_string()];
248 let modifier = picker_density_class(density);
249 if !modifier.is_empty() {
250 parts.push(modifier.to_string());
251 }
252 let inner = picker_density_inner_class(density);
253 if !inner.is_empty() {
254 parts.push(inner.to_string());
255 }
256 parts.join(" ")
257}
258
259pub fn range_field_root_classes(kind: &str, density: Density) -> String {
261 let mut parts = vec![kind.to_string()];
262 let inner = picker_density_inner_class(density);
263 if !inner.is_empty() {
264 parts.push(inner.to_string());
265 }
266 parts.join(" ")
267}