Skip to main content

max / quasi

0.43.0: the webview emitter writes hyperscript, and idiomorph is closed out `0081563e`. Two of the three things taken from the htmx family on 2026-08-08 were a record of a decision nobody had implemented. They close differently. idiomorph was retired rather than implemented. htmx 4 ships `innerMorph` and `outerMorph` as swap styles, so the extension has nothing to supply; that landed with 0.42.0 and this is what marks the adoption closed instead of pending. _hyperscript is in use. The renderer emits programs, from one file, and there is one site today: the chrome of a region that shows its children one at a time. A strip, a disclosure and a prev/position/next row have always been emitted with `data-shows` marks that did nothing at all, so a described carousel needed per-app JavaScript before a reader could reach frame two of bytes already downloaded. A tab now takes `.chosen` from its siblings, moves `aria-selected` across the strip and takes `.current` to the frame it names; a disclosure toggles the one frame under it and reads `aria-expanded` back off it; previous and next read the index off the current frame, wrap in the arithmetic, and write the counter beside them. Permitted by the provenance ruling of 2026-08-18: emitted is fine, hand-written is not. The rule defends against a script nobody remembers is running, and emitted code regenerates from its source every time a screen is drawn. The adoption's one rule is kept and tested: nothing emits a `js` block, which is the only path in the interpreter that reaches `new Function`. Frames carry `data-frame="<region id>"` and `data-shown="<n>"` rather than being found by descent, so a tab group over a gallery steps its own frames and not the gallery's. The handle gate: a program addresses its region by id, inside a CSS attribute selector, inside an HTML attribute, inside a language with `${}` interpolation, so a program is written only when the id is a plain handle and anything else keeps the mark and no program. Escaping was tried and rejected -- a CSS hex escape for `$` is read by browsers and not by every selector engine, which is a program that works where it was tried. `Node::Rich` carries `data-disable-scripting`, the fencing the ruling owed wherever text a user typed becomes markup. Belt and braces, since the markdown pass is the strict preset; what it buys is the guarantee no longer depending on which preset is called. `Shell::hyperscript_src` is the runtime, `without_hyperscript()` drops it, and the scaffolder vendors 0.9.93 beside htmx. The emitted document was driven under the real bundle in jsdom -- stepping, wrapping, the counter, a tab's three marks, the disclosure, and a nested carousel keeping its position while the outer strip moves. `Destination::Local` is still the mark and not the behaviour. What happens locally is named by the member carrying the action, and no member names one yet; `71852b16` is the first that will, and its program belongs in the same file. MNW server, goingson and audiofiles forward-fixed to 0.43 in the same pass.
Author: Max Johnson <me@maxj.phd> · 2026-08-20 16:55 UTC
Signed with PGP, not checked
Commit: 3b403c64727e9c9858b280fb10d9305d00788221
Parent: 26e87ce
21 files changed, +576 insertions, -84 deletions
M Cargo.lock +23 -23
@@ -3404,11 +3404,11 @@
3404 3404
3405 3405 [[package]]
3406 3406 name = "quasi"
3407 - version = "0.42.0"
3407 + version = "0.43.0"
3408 3408
3409 3409 [[package]]
3410 3410 name = "quasi-axum"
3411 - version = "0.42.0"
3411 + version = "0.43.0"
3412 3412 dependencies = [
3413 3413 "axum",
3414 3414 "http",
@@ -3422,7 +3422,7 @@
3422 3422
3423 3423 [[package]]
3424 3424 name = "quasi-basics"
3425 - version = "0.42.0"
3425 + version = "0.43.0"
3426 3426 dependencies = [
3427 3427 "makeover-layout",
3428 3428 "quasi-http",
@@ -3432,7 +3432,7 @@
3432 3432
3433 3433 [[package]]
3434 3434 name = "quasi-bench"
3435 - version = "0.42.0"
3435 + version = "0.43.0"
3436 3436 dependencies = [
3437 3437 "dhat",
3438 3438 "makeover",
@@ -3447,7 +3447,7 @@
3447 3447
3448 3448 [[package]]
3449 3449 name = "quasi-http"
3450 - version = "0.42.0"
3450 + version = "0.43.0"
3451 3451 dependencies = [
3452 3452 "form_urlencoded",
3453 3453 "http",
@@ -3456,7 +3456,7 @@
3456 3456
3457 3457 [[package]]
3458 3458 name = "quasi-immediate"
3459 - version = "0.42.0"
3459 + version = "0.43.0"
3460 3460 dependencies = [
3461 3461 "docengine",
3462 3462 "egui",
@@ -3466,7 +3466,7 @@
3466 3466
3467 3467 [[package]]
3468 3468 name = "quasi-notifs"
3469 - version = "0.42.0"
3469 + version = "0.43.0"
3470 3470 dependencies = [
3471 3471 "quasi-router",
3472 3472 "synckit-config",
@@ -3474,7 +3474,7 @@
3474 3474
3475 3475 [[package]]
3476 3476 name = "quasi-router"
3477 - version = "0.42.0"
3477 + version = "0.43.0"
3478 3478 dependencies = [
3479 3479 "makeover-layout",
3480 3480 ]
@@ -3491,7 +3491,7 @@
3491 3491
3492 3492 [[package]]
3493 3493 name = "quasi-tauri"
3494 - version = "0.42.0"
3494 + version = "0.43.0"
3495 3495 dependencies = [
3496 3496 "http",
3497 3497 "quasi-http",
@@ -3504,7 +3504,7 @@
3504 3504
3505 3505 [[package]]
3506 3506 name = "quasi-tui"
3507 - version = "0.42.0"
3507 + version = "0.43.0"
3508 3508 dependencies = [
3509 3509 "docengine",
3510 3510 "makeover",
@@ -3516,7 +3516,7 @@
3516 3516
3517 3517 [[package]]
3518 3518 name = "quasi-webview"
3519 - version = "0.42.0"
3519 + version = "0.43.0"
3520 3520 dependencies = [
3521 3521 "docengine",
3522 3522 "makeover-layout",
@@ -6187,6 +6187,18 @@
6187 6187 "winnow 1.0.4",
6188 6188 ]
6189 6189
6190 + [[patch.unused]]
6191 + name = "quasi-type"
6192 + version = "0.1.0"
6193 +
6194 + [[patch.unused]]
6195 + name = "makeover-build"
6196 + version = "0.47.0"
6197 +
6198 + [[patch.unused]]
6199 + name = "synckit-client"
6200 + version = "0.8.0"
6201 +
6190 6202 [[patch.unused]]
6191 6203 name = "kberg"
6192 6204 version = "0.1.0"
@@ -6202,15 +6214,3 @@
6202 6214 [[patch.unused]]
6203 6215 name = "tagtree"
6204 6216 version = "0.4.0"
6205 -
6206 - [[patch.unused]]
6207 - name = "quasi-type"
6208 - version = "0.1.0"
6209 -
6210 - [[patch.unused]]
6211 - name = "makeover-build"
6212 - version = "0.47.0"
6213 -
6214 - [[patch.unused]]
6215 - name = "synckit-client"
6216 - version = "0.8.0"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.42.0"
3 + version = "0.43.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.42.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.42.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.43.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.43.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.42.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.43.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.42.0"
3 + version = "0.43.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.42.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.43.0" }
17 17 makeover-layout = "0.31.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.42.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.42.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.43.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.43.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.42.0"
3 + version = "0.43.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.42.0" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.42.0" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.42.0" }
25 + quasi-router = { path = "../quasi-router", version = "0.43.0" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.43.0" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.43.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.42.0" }
31 + quasi-http = { path = "../quasi-http", version = "0.43.0" }
32 32 makeover-layout = "0.31.0"
33 33 makeover-tui = { version = "0.30.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.42.0"
3 + version = "0.43.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.42.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.43.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.42.0"
3 + version = "0.43.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.42.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.43.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.42.0"
3 + version = "0.43.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.42.0", optional = true }
27 + quasi-router = { path = "../quasi-router", version = "0.43.0", optional = true }
28 28 synckit-config = { git = "https://makenot.work/git/max/synckit.git", version = "0.2", optional = true }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-router"
3 - version = "0.42.0"
3 + version = "0.43.0"
4 4 description = "Host-agnostic router: a request in, a renderer-agnostic description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true