| 137 |
137 |
|
//! rules are as generated as the ones here, so they belong in the same layer and
|
| 138 |
138 |
|
//! this crate cannot put them there on the app's behalf.
|
| 139 |
139 |
|
//!
|
|
140 |
+ |
//! # 0.12.0: the ring gets its own width
|
|
141 |
+ |
//!
|
|
142 |
+ |
//! [`focus_rule`] reused [`Emit::border_width`] and emitted a 1px ring. That was
|
|
143 |
+ |
//! an implementation convenience dressed as consistency with the invalid-field
|
|
144 |
+ |
//! ring: a bevel and a focus indicator answer different questions, and only one
|
|
145 |
+ |
//! of them has to be noticed from across a desk.
|
|
146 |
+ |
//!
|
|
147 |
+ |
//! Caught while adopting 0.11.0 into goingson, by the check the adoption tasks
|
|
148 |
+ |
//! ask for. Every consumer had already written its own ring and all three chose
|
|
149 |
+ |
//! at least 2px: the MNW server 2px across 10 rules, Balanced Breakfast 2px,
|
|
150 |
+ |
//! goingson 2px on three rules and 3px on the one covering twelve selectors. The
|
|
151 |
+ |
//! design system was the only thing in the tree saying 1px, so deleting the app
|
|
152 |
+ |
//! rules in favour of it would have thinned the focus indicator everywhere.
|
|
153 |
+ |
//!
|
|
154 |
+ |
//! [`Emit::focus_width`] now carries it, defaulting to `2px`, and the offset is
|
|
155 |
+ |
//! the same magnitude with its sign off the depth. Both values are the measured
|
|
156 |
+ |
//! consensus rather than a new opinion.
|
|
157 |
+ |
//!
|
| 140 |
158 |
|
//! # Substitution, three ways
|
| 141 |
159 |
|
//!
|
| 142 |
160 |
|
//! `Fill::Well` has no colour on makeover before 2.3.0, and each renderer
|
| 174 |
192 |
|
/// A value, so it arrives from the caller: border widths belong to
|
| 175 |
193 |
|
/// `makeover-geometry` and will come from there once it carries them.
|
| 176 |
194 |
|
pub border_width: &'static str,
|
|
195 |
+ |
/// Focus ring thickness, as a CSS length.
|
|
196 |
+ |
///
|
|
197 |
+ |
/// Separate from [`border_width`](Self::border_width), which it reused
|
|
198 |
+ |
/// until 0.12.0. That reuse was an implementation convenience dressed as
|
|
199 |
+ |
/// consistency, and it emitted a 1px ring: a bevel and a focus indicator
|
|
200 |
+ |
/// are answering different questions, and only one of them has to be
|
|
201 |
+ |
/// noticed from across a desk.
|
|
202 |
+ |
///
|
|
203 |
+ |
/// The default is the measured consensus rather than a new opinion. Every
|
|
204 |
+ |
/// consumer had already written its own ring and all three chose at least
|
|
205 |
+ |
/// 2px: the MNW server 2px across 10 rules, Balanced Breakfast 2px,
|
|
206 |
+ |
/// goingson 2px on three rules and 3px on the one covering twelve
|
|
207 |
+ |
/// selectors. The design system was the only thing in the tree saying 1px.
|
|
208 |
+ |
pub focus_width: &'static str,
|
| 177 |
209 |
|
/// Prefix for emitted class names, without the leading dot.
|
| 178 |
210 |
|
pub class_prefix: &'static str,
|
| 179 |
211 |
|
}
|
| 182 |
214 |
|
fn default() -> Self {
|
| 183 |
215 |
|
Self {
|
| 184 |
216 |
|
border_width: "1px",
|
|
217 |
+ |
focus_width: "2px",
|
| 185 |
218 |
|
class_prefix: "",
|
| 186 |
219 |
|
}
|
| 187 |
220 |
|
}
|
| 363 |
396 |
|
/// They render the same: both are a flush ring one border-width wide.
|
| 364 |
397 |
|
#[must_use]
|
| 365 |
398 |
|
pub fn focus_rule(selector: &str, depth: Depth, opts: &Emit) -> String {
|
| 366 |
|
- |
let w = opts.border_width;
|
|
399 |
+ |
let w = opts.focus_width;
|
|
400 |
+ |
// Same magnitude either way, and only the sign comes off the depth. Both
|
|
401 |
+ |
// values are what the consumers had already converged on independently:
|
|
402 |
+ |
// 2px out is what all three wrote, and 2px in is the MNW server's own
|
|
403 |
+ |
// answer for the one inset ring it had.
|
| 367 |
404 |
|
let offset = match depth.bevel() {
|
| 368 |
|
- |
// Inside the well, clear of the inset edge rather than painted over
|
| 369 |
|
- |
// it. Two widths in: one to cross the edge, one to stand off it.
|
| 370 |
|
- |
Some(Bevel::Inset) => format!("calc(-2 * {w})"),
|
|
405 |
+ |
// Inside the well, clear of its edge rather than painted over it.
|
|
406 |
+ |
Some(Bevel::Inset) => format!("calc(-1 * {w})"),
|
| 371 |
407 |
|
// Raised, or no edge at all. Outside, standing off by its own width.
|
| 372 |
408 |
|
_ => w.to_string(),
|
| 373 |
409 |
|
};
|
| 950 |
986 |
|
// no bevel to restate beside it and nothing to keep in agreement.
|
| 951 |
987 |
|
let opts = Emit::default();
|
| 952 |
988 |
|
let css = focus_rule("button", Depth::Raised, &opts);
|
| 953 |
|
- |
assert!(css.contains("outline: 1px solid var(--focus-ring)"));
|
|
989 |
+ |
assert!(css.contains("outline: 2px solid var(--focus-ring)"));
|
| 954 |
990 |
|
assert!(!css.contains("box-shadow"), "the ring restated the bevel");
|
| 955 |
991 |
|
}
|
| 956 |
992 |
|
|
| 960 |
996 |
|
// not off a per-component choice, which is what gave three apps three
|
| 961 |
997 |
|
// different rings.
|
| 962 |
998 |
|
let opts = Emit::default();
|
| 963 |
|
- |
assert!(focus_rule("field", Depth::Well, &opts).contains("outline-offset: calc(-2 * 1px)"));
|
| 964 |
|
- |
assert!(focus_rule("button", Depth::Raised, &opts).contains("outline-offset: 1px"));
|
|
999 |
+ |
assert!(focus_rule("field", Depth::Well, &opts).contains("outline-offset: calc(-1 * 2px)"));
|
|
1000 |
+ |
assert!(focus_rule("button", Depth::Raised, &opts).contains("outline-offset: 2px"));
|
| 965 |
1001 |
|
// Nothing to sit inside of, so it sits outside.
|
| 966 |
|
- |
assert!(focus_rule("badge", Depth::Sunken, &opts).contains("outline-offset: 1px"));
|
|
1002 |
+ |
assert!(focus_rule("badge", Depth::Sunken, &opts).contains("outline-offset: 2px"));
|
|
1003 |
+ |
|
|
1004 |
+ |
// And the ring is not the bevel. Reusing border_width emitted a 1px
|
|
1005 |
+ |
// ring that every consumer had already overridden.
|
|
1006 |
+ |
assert_ne!(opts.focus_width, opts.border_width);
|
| 967 |
1007 |
|
}
|
| 968 |
1008 |
|
|
| 969 |
1009 |
|
#[test]
|
| 1289 |
1329 |
|
// list never covered: `border_width` arrives from `Emit` and lands
|
| 1290 |
1330 |
|
// bare in the focus ring's offset, where the bevel had only ever
|
| 1291 |
1331 |
|
// used it inside an `inset` shadow.
|
| 1292 |
|
- |
let width = Emit::default().border_width;
|
|
1332 |
+ |
let opts = Emit::default();
|
| 1293 |
1333 |
|
assert!(
|
| 1294 |
1334 |
|
value.contains("inset")
|
| 1295 |
|
- |
|| value.contains(width)
|
|
1335 |
+ |
|| value.contains(opts.border_width)
|
|
1336 |
+ |
|| value.contains(opts.focus_width)
|
| 1296 |
1337 |
|
|| matches!(
|
| 1297 |
1338 |
|
value.trim_end_matches(';'),
|
| 1298 |
1339 |
|
"0" | "1" | "none" | "auto" | "not-allowed"
|