| 261 |
261 |
|
|
| 262 |
262 |
|
let field = class("field", opts);
|
| 263 |
263 |
|
css.push_str(&depth_rule(&field, Depth::Well));
|
| 264 |
|
- |
// `Field::invalid` marks the whole group rather than only the message, so
|
| 265 |
|
- |
// the ring goes on the control. Flat, not a two-tone bevel: this edge is
|
| 266 |
|
- |
// saying "wrong", and lighting one side of it would have it say "raised"
|
| 267 |
|
- |
// at the same time.
|
|
264 |
+ |
|
|
265 |
+ |
// Keyed on the ARIA attribute rather than on a class, so the visual state
|
|
266 |
+ |
// and the accessible state cannot drift apart: there is one fact and both
|
|
267 |
+ |
// read it. goingson already drove its invalid styling this way and was
|
|
268 |
+ |
// right to; the `.invalid` class this emitted before 0.5.0 was a second
|
|
269 |
+ |
// place to forget.
|
|
270 |
+ |
//
|
|
271 |
+ |
// The ring composes *after* the bevel rather than replacing it. box-shadow
|
|
272 |
+ |
// is not additive, so a lone ring silently dropped the well out from under
|
|
273 |
+ |
// an invalid field. Flat and unlit: this edge is saying "wrong", and
|
|
274 |
+ |
// lighting one side would have it say "raised" at the same time.
|
| 268 |
275 |
|
let _ = writeln!(
|
| 269 |
276 |
|
css,
|
| 270 |
|
- |
".{field}.invalid {{\n box-shadow: inset 0 0 0 {} var(--danger);\n}}",
|
|
277 |
+ |
".{field}[aria-invalid=\"true\"] {{\n box-shadow: var({}), 0 0 0 {} var(--danger);\n}}",
|
|
278 |
+ |
bevel_var(Bevel::Inset),
|
| 271 |
279 |
|
opts.border_width
|
| 272 |
280 |
|
);
|
| 273 |
281 |
|
css
|
| 728 |
736 |
|
fn an_invalid_field_is_ringed_without_being_lit() {
|
| 729 |
737 |
|
let css = surface_rules(&Emit::default());
|
| 730 |
738 |
|
assert!(css.contains(".field {"));
|
| 731 |
|
- |
assert!(css.contains(".field.invalid {"));
|
|
739 |
+ |
// The ARIA attribute, not a class: one fact, read by both the visual
|
|
740 |
+ |
// and the accessible state, so they cannot drift.
|
|
741 |
+ |
assert!(css.contains(".field[aria-invalid=\"true\"] {"));
|
|
742 |
+ |
assert!(!css.contains(".field.invalid"));
|
| 732 |
743 |
|
// A flat ring: this edge says "wrong", and a two-tone bevel would have
|
| 733 |
744 |
|
// it say "raised" at the same time.
|
| 734 |
|
- |
assert!(css.contains("inset 0 0 0 1px var(--danger)"));
|
|
745 |
+ |
assert!(css.contains("0 0 0 1px var(--danger)"));
|
|
746 |
+ |
}
|
|
747 |
+ |
|
|
748 |
+ |
#[test]
|
|
749 |
+ |
fn an_invalid_field_keeps_the_well_underneath_it() {
|
|
750 |
+ |
// box-shadow is not additive. A lone ring replaces the bevel and drops
|
|
751 |
+ |
// the well out from under the field, which is what this emitted before
|
|
752 |
+ |
// 0.5.0 and is the whole reason the rule composes.
|
|
753 |
+ |
let css = surface_rules(&Emit::default());
|
|
754 |
+ |
let invalid = css
|
|
755 |
+ |
.lines()
|
|
756 |
+ |
.skip_while(|l| !l.starts_with(".field[aria-invalid"))
|
|
757 |
+ |
.take_while(|l| !l.starts_with('}'))
|
|
758 |
+ |
.collect::<Vec<_>>()
|
|
759 |
+ |
.join("\n");
|
|
760 |
+ |
assert!(
|
|
761 |
+ |
invalid.contains("var(--bevel-inset)"),
|
|
762 |
+ |
"the well was dropped: {invalid}"
|
|
763 |
+ |
);
|
|
764 |
+ |
assert!(invalid.contains("var(--danger)"));
|
| 735 |
765 |
|
}
|
| 736 |
766 |
|
|
| 737 |
767 |
|
#[test]
|