Skip to main content

max / makeover-webview

0.70.1: give a nested row a rule, so a described outline indents Decided in quasicoherent edf33114 (Max). makeover-layout names the concept as Nesting; this is the rule. Measured 2026-08-30: quasi-webview has emitted `row-nested` with `style="--row-depth:N"` on every described hierarchy since 674dc30f, plus `row-branch` and a `row-disclose` chevron, and NO stylesheet anywhere in the tree read any of it. So a described outline in a browser was a flat list with chevrons in it -- the folding worked and the indent did not exist. The magnitude is a custom property with a fallback, which is this crate's own shape: --awaiting-gap is the precedent. What a level IS stays the description's; what it is WORTH is this renderer's, and an app overriding --row-indent is how a level becomes worth more or less. Padding and not margin. A row is a box that can be selected and hovered, and indenting with margin would take the indent out of the highlight -- the shading under a nested row would start where its text does rather than where its row does. Here rather than in each app, and that was a live option rather than an oversight: row-select, row-current and row-chosen are app-styled by design, but an indent is not decoration. It is what the description means, and three apps agreeing about it by accident is not agreement. A patch, for the reason makeover-layout 0.41.1 gives: three CSS rules is additive, nothing here uses the new type, and the two releases are independent.
Author: Max Johnson <me@maxj.phd> · 2026-08-30 23:49 UTC
Signed with PGP, not checked
Commit: 7942bd7bf31c4f57bf12fd0b08e912343910a612
Parent: e412a9f
4 files changed, +102 insertions, -2 deletions
M Cargo.toml +1 -1
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makeover-webview"
3 - version = "0.70.0"
3 + version = "0.70.1"
4 4 edition = "2024"
5 5 # One copy of this renderer per dependency graph, enforced by cargo rather than
6 6 # by remembering. Two versions means the generated stylesheet and the emitted
M src/lib.rs +90
@@ -1144,6 +1144,57 @@
1144 1144 lines = Flow::Relaxed.lines()
1145 1145 );
1146 1146
1147 + // A row inside a hierarchy: a tree, an outline, a threaded list.
1148 + // `edf33114`, decided 2026-08-30 (Max). makeover-layout names the concept
1149 + // as `Nesting` -- deliberately not `Depth`, which is surface bevel in that
1150 + // crate -- and this is the rule.
1151 + //
1152 + // Measured 2026-08-30: quasi-webview has been emitting `row-nested` with
1153 + // `style="--row-depth:N"` on every described hierarchy, and **no stylesheet
1154 + // anywhere in the tree read any of it**. So a described outline in a
1155 + // browser was a flat list with chevrons in it -- the folding worked and the
1156 + // indent did not exist.
1157 + //
1158 + // The magnitude is a custom property with a fallback, which is this crate's
1159 + // own shape: `--awaiting-gap` above is the precedent, and an app overriding
1160 + // `--row-indent` is how a level becomes worth more or less. What a level IS
1161 + // stays the description's; what it is WORTH is a renderer's, and a terminal
1162 + // spending columns for the same fact is not disagreeing.
1163 + //
1164 + // Here rather than in each app, and that was a live option rather than an
1165 + // oversight. `row-select`, `row-current` and `row-chosen` are app-styled by
1166 + // design; the indent is not decoration, it is what the description MEANS,
1167 + // and three apps agreeing about it by accident is not agreement.
1168 + //
1169 + // `padding` and not `margin`: a row is a box that can be selected and
1170 + // hovered, and indenting with margin would take the indent out of the
1171 + // highlight, so the shading under a nested row would start where its text
1172 + // does rather than where its row does.
1173 + let _ = writeln!(
1174 + css,
1175 + ".{} {{\n padding-inline-start: calc(var(--row-depth, 0) * var(--row-indent, 1.5ch));\n}}",
1176 + class("row-nested", opts)
1177 + );
1178 +
1179 + // The two halves of a branch, emitted by quasi-webview and unstyled until
1180 + // now for the same reason.
1181 + //
1182 + // A branch row is the one a reader can fold, and the chevron is its hit
1183 + // target. The chevron is drawn by the app or the description -- this says
1184 + // where it sits and how big the target is, which is the accessibility fact
1185 + // rather than the decorative one: a control smaller than this is one a
1186 + // finger misses.
1187 + let _ = writeln!(
1188 + css,
1189 + ".{} {{\n display: flex;\n align-items: baseline;\n gap: var(--row-disclose-gap, 0.5ch);\n}}",
1190 + class("row-branch", opts)
1191 + );
1192 + let _ = writeln!(
1193 + css,
1194 + ".{} {{\n flex: none;\n min-inline-size: var(--tap-target, 2rem);\n min-block-size: var(--tap-target, 2rem);\n background: none;\n border: 0;\n color: inherit;\n cursor: pointer;\n}}",
1195 + class("row-disclose", opts)
1196 + );
1197 +
1147 1198 css
1148 1199 }
1149 1200
@@ -3059,6 +3110,45 @@
3059 3110 fn a_relaxed_part_clamps_and_a_tight_one_says_nothing() {
3060 3111 let css = stylesheet(&Emit::default());
3061 3112 assert!(css.contains(".row-relaxed {"));
3113 + }
3114 +
3115 + /// `edf33114`. The done condition: a row carrying a level indents in a
3116 + /// browser with no app-authored CSS.
3117 + ///
3118 + /// quasi-webview has emitted `row-nested` with `--row-depth` on every
3119 + /// described hierarchy since `674dc30f`, and nothing in the tree read it --
3120 + /// so a described outline was a flat list with chevrons in it.
3121 + #[test]
3122 + fn a_nested_row_indents_by_its_level_and_an_app_can_say_what_a_level_is_worth() {
3123 + let css = stylesheet(&Emit::default());
3124 +
3125 + assert!(css.contains(".row-nested {"), "{css}");
3126 + assert!(
3127 + css.contains(
3128 + "padding-inline-start: calc(var(--row-depth, 0) * var(--row-indent, 1.5ch));"
3129 + ),
3130 + "{css}"
3131 + );
3132 + // The magnitude is a custom property with a fallback, which is
3133 + // `--awaiting-gap`'s shape: what a level IS stays the description's and
3134 + // what it is WORTH is this renderer's, overridable by an app. Padding
3135 + // rather than margin, so the indent is inside the box a selection
3136 + // shades.
3137 + assert!(
3138 + !css.contains("margin-inline-start: calc(var(--row-depth"),
3139 + "{css}"
3140 + );
3141 +
3142 + // The branch and its chevron, emitted and unstyled for the same reason.
3143 + assert!(css.contains(".row-branch {"), "{css}");
3144 + assert!(css.contains(".row-disclose {"), "{css}");
3145 +
3146 + for name in ["row-nested", "row-branch", "row-disclose"] {
3147 + assert!(
3148 + crate::vocabulary::names(&Emit::default()).contains(name),
3149 + "{name} is declared"
3150 + );
3151 + }
3062 3152 assert!(css.contains("-webkit-line-clamp: 2;"));
3063 3153 // The count is `Flow`'s, not this crate's. If the tier ever means three
3064 3154 // lines, this fails here rather than in an app.
@@ -367,6 +367,14 @@
367 367 /// for an unknown flow is correct rather than lossy.
368 368 pub const FLOW_CLASSES: &[&str] = &["row-relaxed"];
369 369
370 + /// The classes a row inside a hierarchy carries.
371 + ///
372 + /// `edf33114`. Emitted by quasi-webview since `674dc30f` and styled by nothing
373 + /// until 2026-08-30, which is why they are declared here now: the generated
374 + /// sheet defines rules for them, so the vocabulary has to say it does or the
375 + /// check that every emitted name has a rule cannot see them.
376 + pub const NESTING_CLASSES: &[&str] = &["row-nested", "row-branch", "row-disclose"];
377 +
370 378 /// The class for a part's flow, if it needs one.
371 379 ///
372 380 /// `None` for [`Flow::Tight`] and for any tier added upstream that this crate
@@ -38,7 +38,8 @@
38 38 use crate::figure::FIGURE_CLASSES;
39 39 use crate::form::{FIELD_CLASSES, FIELD_STATE_CLASSES};
40 40 use crate::list::{
41 - CELL_DROP_CLASSES, CELL_PART_CLASSES, CELL_WIDTH_CLASSES, FLOW_CLASSES, ROW_PART_CLASSES,
41 + CELL_DROP_CLASSES, CELL_PART_CLASSES, CELL_WIDTH_CLASSES, FLOW_CLASSES, NESTING_CLASSES,
42 + ROW_PART_CLASSES,
42 43 };
43 44 use crate::meter::METER_CLASSES;
44 45 use crate::placeholder::PLACEHOLDER_CLASSES;
@@ -91,6 +92,7 @@
91 92 .chain(CELL_WIDTH_CLASSES)
92 93 .chain(CELL_DROP_CLASSES)
93 94 .chain(FLOW_CLASSES)
95 + .chain(NESTING_CLASSES)
94 96 .chain(crate::RUN_CLASSES)
95 97 .chain(FACET_CLASSES)
96 98 .chain(FIELD_CLASSES)