Skip to main content

max / quasi

0.69.0: a control may show a picture, and half the brief was stale `db998898`, filed 2026-08-22 with a standing instruction that the measuring was the first half of the task. It was, and it changed the answer. The brief's wider claim stopped being true after it was filed. It said `Cell::new` and `Row::new` both take a string, "so a picture cannot sit beside a control in a table or a list either", offered as option (b), the big change. The containment model shipped since: `Row::part` and `Cell::part` take any leaf, `Node::Image` declares `Containment::Text`, and the webview puts an activated row's whole run inside the anchor. Emitted one to check, and a picture inside an activated row is already pressable with no member at all. Option (b) was done. What that leaves is the case a row cannot be: the control itself is the picture. Two sites, which clears the bar the task set, since one consumer is a shape and not a gap. media_picker.rs `fn card` -- the tile is a region holding an image and an act as siblings, so only the file name answers a press and a reader aiming at the thumbnail hits nothing. It cannot be an activated row instead, because the press deposits a value and `Fill` lives on `Act`. templates/pages/project.html:135 -- `<a class="item-thumbnail"><img></a>`, with a second link on the title going to the same place. One act showing the cover and labelled with the title is one control where the markup has two adjacent links to one destination. Measured and NOT consumers, recorded so the next pass does not redo them: gallery.js (the tile is a div, the picture decorative, the controls glyph buttons), purchase.html (same markup, a div), discover_results.html (already one link, thumbnail is text, describable today as an activated row), quasi-basics::carousel, audiofiles' file list, Balanced Breakfast, goingson. `Act::shows: Option<Picture>`, with `Act::showing`. The label stays what the control says and the picture is what it shows, and a renderer draws both: a control drawing only a picture and hiding its name has no accessible text. A webview writes the `<img>` inside the control, sharing one emitter with a picture in a region body so the two cannot drift -- the `<img>` was extracted for that and the 302 existing tests pin it as unchanged. quasi-immediate draws it above the button, grouped, outside `makeover_immediate::widget::act` for `Act::hint`'s reason. quasi-tui ignores it and draws the label, which the brief predicted and which is right: alt text is all a terminal has of a picture, and the label is already saying the name. `Outcome`'s `#[expect(clippy::large_enum_variant)]` goes back on, which is that type's own recorded instruction rather than a new call. `Picture` is 88 bytes, an `Act` is now 464 and the enum 520 against `Locating`'s 272. Boxing the node is refused as before; boxing the picture is refused for a second reason, that it would put an allocation in the public shape to save stack on a value built once per request. Consumers forward-fixed in the same pass: MNW server, goingson and audiofiles move to `^0.69` and each compiles and tests green.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-27 18:11 UTC
Signed with PGP, not checked
Commit: 6d58f6192a49e2d83c3bbd6895e13dc7b20e76e8
Parent: 19f459b
18 files changed, +253 insertions, -86 deletions
M Cargo.lock +8 -8
@@ -6211,6 +6211,14 @@
6211 6211 "winnow 1.0.4",
6212 6212 ]
6213 6213
6214 + [[patch.unused]]
6215 + name = "quasi-type"
6216 + version = "0.1.0"
6217 +
6218 + [[patch.unused]]
6219 + name = "synckit-client"
6220 + version = "0.9.1"
6221 +
6214 6222 [[patch.unused]]
6215 6223 name = "kberg"
6216 6224 version = "0.1.0"
@@ -6226,11 +6234,3 @@
6226 6234 [[patch.unused]]
6227 6235 name = "tagtree"
6228 6236 version = "0.4.1"
6229 -
6230 - [[patch.unused]]
6231 - name = "quasi-type"
6232 - version = "0.1.0"
6233 -
6234 - [[patch.unused]]
6235 - name = "synckit-client"
6236 - version = "0.9.1"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.68.0"
3 + version = "0.69.0"
4 4 description = "The axum host adapter for quasi-router: an HTTP request in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,14 +13,14 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.68.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.68.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.69.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.69.0" }
18 18 axum = "0.8.8"
19 19 http = "1.3.1"
20 20 tokio = { version = "1.50.0", features = ["rt"] }
21 21
22 22 [dev-dependencies]
23 - quasi-webview = { path = "../quasi-webview", version = "0.68.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.69.0" }
24 24 tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread"] }
25 25 tower = { version = "0.5.3", features = ["util"] }
26 26 http-body-util = "0.1.3"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-basics"
3 - version = "0.68.0"
3 + version = "0.69.0"
4 4 description = "The first-party widget set: named assemblies of primitives, shared across our apps"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,12 +13,12 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.68.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.69.0" }
17 17 makeover-layout = "0.35.0"
18 18
19 19 [dev-dependencies]
20 20 # A widget's guarantees are claims about what a renderer draws, so they are
21 21 # tested against a real one rather than by walking the tree the assembly just
22 22 # built. The webview is the renderer that recognises names today.
23 - quasi-webview = { path = "../quasi-webview", version = "0.68.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.68.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.69.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.69.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.68.0"
3 + version = "0.69.0"
4 4 description = "What a described screen costs to render, in time and in allocations"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -22,13 +22,13 @@
22 22 count = ["dep:dhat"]
23 23
24 24 [dependencies]
25 - quasi-router = { path = "../quasi-router", version = "0.68.0" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.68.0" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.68.0" }
25 + quasi-router = { path = "../quasi-router", version = "0.69.0" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.69.0" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.69.0" }
28 28 # `Serves` is the trait carrying `screen` and `fragment`, which is what the
29 29 # webview is measured through. Taken directly rather than through quasi-webview
30 30 # because a bench calling a trait method should name the trait it calls.
31 - quasi-http = { path = "../quasi-http", version = "0.68.0" }
31 + quasi-http = { path = "../quasi-http", version = "0.69.0" }
32 32 makeover-layout = "0.35.0"
33 33 makeover-tui = { version = "0.35.0", features = ["theme"] }
34 34 # Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-http"
3 - version = "0.68.0"
3 + version = "0.69.0"
4 4 description = "The http-shaped seam quasi's webview host adapters share: decoding in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,6 +13,6 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.68.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.69.0" }
17 17 http = "1.3.1"
18 18 form_urlencoded = "1.2.2"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-immediate"
3 - version = "0.68.0"
3 + version = "0.69.0"
4 4 edition = "2024"
5 5 description = "The immediate-mode renderer for quasi-router: a described screen in, an egui frame out. Immediate mode is the constraint that matters, not the library."
6 6 license = "MIT"
@@ -12,7 +12,7 @@
12 12 categories = ["gui"]
13 13
14 14 [dependencies]
15 - quasi-router = { path = "../quasi-router", version = "0.68.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.69.0" }
16 16 # The node drawing, which is the makeover layer's and not this crate's. Every
17 17 # widget here that is not a container comes from it: a screen walk that painted
18 18 # its own meter would be the divergence the suite exists to end, one copy per
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-notifs"
3 - version = "0.68.0"
3 + version = "0.69.0"
4 4 description = "Declared notification kinds and the registry that holds them: what a notification says and what it is for, apart from how it reaches a person"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -24,5 +24,5 @@
24 24 describe = ["dep:quasi-router"]
25 25
26 26 [dependencies]
27 - quasi-router = { path = "../quasi-router", version = "0.68.0", optional = true }
27 + quasi-router = { path = "../quasi-router", version = "0.69.0", optional = true }
28 28 synckit-config = { git = "https://makenot.work/git/max/synckit.git", version = "0.2", optional = true }