| 157 |
157 |
|
Depth::Flat => return None,
|
| 158 |
158 |
|
Depth::Raised => "raised",
|
| 159 |
159 |
|
Depth::Well => "well",
|
|
160 |
+ |
Depth::Sunken => "sunken",
|
| 160 |
161 |
|
};
|
| 161 |
162 |
|
Some(format!("{}{name}", opts.class_prefix))
|
| 162 |
163 |
|
}
|
| 172 |
173 |
|
/// Callers lean on the emptiness to skip the rule rather than emit a class that
|
| 173 |
174 |
|
/// sets nothing: a class that sets no properties is a class that means "I
|
| 174 |
175 |
|
/// thought about this", which is what comments are for.
|
|
176 |
+ |
///
|
|
177 |
+ |
/// The two halves are emitted independently because [`Depth::Sunken`] has a
|
|
178 |
+ |
/// fill and no bevel. Requiring both, which this did before makeover-layout
|
|
179 |
+ |
/// 0.3.0, silently dropped the fill for exactly that case. Independent does not
|
|
180 |
+ |
/// mean unpaired: both halves still come off one `Depth`, so they cannot
|
|
181 |
+ |
/// disagree about what the region is.
|
| 175 |
182 |
|
#[must_use]
|
| 176 |
183 |
|
pub fn depth_declarations(depth: Depth) -> String {
|
| 177 |
|
- |
let (Some(fill), Some(bevel)) = (depth.fill(), depth.bevel()) else {
|
| 178 |
|
- |
return String::new();
|
| 179 |
|
- |
};
|
| 180 |
|
- |
format!(
|
| 181 |
|
- |
" background: {};\n box-shadow: var({});\n",
|
| 182 |
|
- |
fill_var(fill),
|
| 183 |
|
- |
bevel_var(bevel)
|
| 184 |
|
- |
)
|
|
184 |
+ |
let mut css = String::new();
|
|
185 |
+ |
if let Some(fill) = depth.fill() {
|
|
186 |
+ |
let _ = writeln!(css, " background: {};", fill_var(fill));
|
|
187 |
+ |
}
|
|
188 |
+ |
if let Some(bevel) = depth.bevel() {
|
|
189 |
+ |
let _ = writeln!(css, " box-shadow: var({});", bevel_var(bevel));
|
|
190 |
+ |
}
|
|
191 |
+ |
css
|
| 185 |
192 |
|
}
|
| 186 |
193 |
|
|
| 187 |
194 |
|
/// One rule giving a selector a depth, or nothing when the depth declares
|
| 319 |
326 |
|
///
|
| 320 |
327 |
|
/// [`Selector::abutting`] is not emitted: whether the options touch is
|
| 321 |
328 |
|
/// spacing, and spacing is `makeover-geometry`'s question to answer.
|
|
329 |
+ |
///
|
|
330 |
+ |
/// Both states emit as of makeover-layout 0.3.0. Before it the description
|
|
331 |
+ |
/// named only the chosen option, so an unchosen one fell through to
|
|
332 |
+ |
/// [`Depth::Flat`] and nothing was drawn for it, which left goingson's tab
|
|
333 |
+ |
/// strip hand-writing the recess that makes its chosen tab read as forward.
|
| 322 |
334 |
|
fn selector_rules(opts: &Emit) -> String {
|
| 323 |
335 |
|
let mut css = String::new();
|
| 324 |
336 |
|
for (selector, name) in [
|
| 326 |
338 |
|
(Selector::Segmented, "segment"),
|
| 327 |
339 |
|
(Selector::Toggle, "toggle"),
|
| 328 |
340 |
|
] {
|
| 329 |
|
- |
// The unchosen option is flat and emits no depth of its own. Giving it
|
| 330 |
|
- |
// an edge would make every option look picked.
|
| 331 |
341 |
|
let c = class(name, opts);
|
|
342 |
+ |
css.push_str(&depth_rule(&c, selector.unchosen()));
|
| 332 |
343 |
|
css.push_str(&interactive_rules(&c));
|
| 333 |
344 |
|
css.push_str(&depth_rule(&format!("{c}.chosen"), selector.chosen()));
|
| 334 |
345 |
|
}
|
| 510 |
521 |
|
// raised region reads as a well, and makeover says outright that
|
| 511 |
522 |
|
// surface-sunken cannot serve as one, so the app is the thing that
|
| 512 |
523 |
|
// moves.
|
|
524 |
+ |
//
|
|
525 |
+ |
// Scoped to the pressed rules rather than to the whole sheet: since
|
|
526 |
+ |
// makeover-layout 0.3.0 an unchosen tab is legitimately
|
|
527 |
+ |
// --surface-sunken, so the token appearing somewhere in the output no
|
|
528 |
+ |
// longer means the app's choice leaked in.
|
| 513 |
529 |
|
let css = stylesheet(&Emit::default());
|
| 514 |
|
- |
assert!(
|
| 515 |
|
- |
!css.contains("surface-sunken"),
|
| 516 |
|
- |
"the app's pressed fill leaked into the generated sheet"
|
| 517 |
|
- |
);
|
|
530 |
+ |
let mut checked = 0;
|
|
531 |
+ |
for rule in css.split("}\n") {
|
|
532 |
+ |
if !rule.contains(":active") {
|
|
533 |
+ |
continue;
|
|
534 |
+ |
}
|
|
535 |
+ |
checked += 1;
|
|
536 |
+ |
assert!(
|
|
537 |
+ |
!rule.contains("surface-sunken"),
|
|
538 |
+ |
"a pressed rule took the app's fill: {rule}"
|
|
539 |
+ |
);
|
|
540 |
+ |
}
|
|
541 |
+ |
assert!(checked > 0, "no pressed rules found to check");
|
| 518 |
542 |
|
assert_eq!(
|
| 519 |
543 |
|
Depth::Raised.pressed().fill(),
|
| 520 |
544 |
|
Some(Fill::Well),
|
| 595 |
619 |
|
}
|
| 596 |
620 |
|
|
| 597 |
621 |
|
#[test]
|
| 598 |
|
- |
fn an_unchosen_option_has_no_edge_of_its_own() {
|
|
622 |
+ |
fn an_unchosen_tab_recedes_without_looking_picked() {
|
| 599 |
623 |
|
let css = selector_rules(&Emit::default());
|
| 600 |
|
- |
// `.tab {` with a body would make every option look picked. Only the
|
| 601 |
|
- |
// interaction states and the chosen rule may exist.
|
| 602 |
|
- |
assert!(!css.contains(".tab {\n"));
|
|
624 |
+ |
// Recessed by colour and given no edge. An edge would make every option
|
|
625 |
+ |
// look picked; flat would leave the chosen one nothing to come forward
|
|
626 |
+ |
// from, which is the gap makeover-layout 0.3.0 closed.
|
|
627 |
+ |
assert!(
|
|
628 |
+ |
css.contains(".tab {\n background: var(--surface-sunken);\n}"),
|
|
629 |
+ |
"unchosen tab is not recessed: {css}"
|
|
630 |
+ |
);
|
|
631 |
+ |
assert_eq!(Selector::Tabs.unchosen(), Depth::Sunken);
|
| 603 |
632 |
|
assert!(css.contains(".tab:hover {"));
|
| 604 |
633 |
|
}
|
| 605 |
634 |
|
|
|
635 |
+ |
#[test]
|
|
636 |
+ |
fn a_segment_stands_up_so_the_chosen_one_can_be_held_in() {
|
|
637 |
+ |
// The inverse of the tab, and why the three selectors are not one
|
|
638 |
+ |
// member with a flag.
|
|
639 |
+ |
let css = selector_rules(&Emit::default());
|
|
640 |
+ |
assert!(css.contains(".segment {\n background: var(--surface-raised);"));
|
|
641 |
+ |
assert_eq!(Selector::Segmented.unchosen(), Depth::Raised);
|
|
642 |
+ |
assert_eq!(Selector::Segmented.chosen(), Depth::Well);
|
|
643 |
+ |
}
|
|
644 |
+ |
|
| 606 |
645 |
|
#[test]
|
| 607 |
646 |
|
fn row_actions_are_revealed_without_moving_the_row() {
|
| 608 |
647 |
|
let css = row_rules(&Emit::default());
|