| 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 |
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.
|