max / quasi
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
8 files changed,
+79 insertions,
-41 deletions
| @@ -2297,8 +2297,6 @@ | |||
| 2297 | 2297 | [[package]] | |
| 2298 | 2298 | name = "makeover-immediate" | |
| 2299 | 2299 | version = "0.18.0" | |
| 2300 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2301 | - | checksum = "333aefe3ef5c2c8df2df1fc7adf7a54613afaf58107e89916b0d0d6ca488dd6e" | |
| 2302 | 2300 | dependencies = [ | |
| 2303 | 2301 | "egui", | |
| 2304 | 2302 | "egui_extras", | |
| @@ -2307,15 +2305,11 @@ | |||
| 2307 | 2305 | ||
| 2308 | 2306 | [[package]] | |
| 2309 | 2307 | name = "makeover-layout" | |
| 2310 | - | version = "0.19.0" | |
| 2311 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2312 | - | checksum = "2c5e6bd13bcf40df8f4eae9736591a1ecef32aedc7205eb497e0633a8a9d2b35" | |
| 2308 | + | version = "0.20.0" | |
| 2313 | 2309 | ||
| 2314 | 2310 | [[package]] | |
| 2315 | 2311 | name = "makeover-touch" | |
| 2316 | 2312 | version = "0.12.0" | |
| 2317 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2318 | - | checksum = "6a9314d98c2a457b901cb93274b3b39686a67a198499eeee407b978dae7aa054" | |
| 2319 | 2313 | dependencies = [ | |
| 2320 | 2314 | "makeover-geometry", | |
| 2321 | 2315 | "makeover-layout", | |
| @@ -2323,9 +2317,7 @@ | |||
| 2323 | 2317 | ||
| 2324 | 2318 | [[package]] | |
| 2325 | 2319 | name = "makeover-tui" | |
| 2326 | - | version = "0.18.0" | |
| 2327 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2328 | - | checksum = "a9a012eac65ca4284b98b4da74f23bbd7753d046e2cce15b764bf8913b1a9d8d" | |
| 2320 | + | version = "0.19.0" | |
| 2329 | 2321 | dependencies = [ | |
| 2330 | 2322 | "makeover", | |
| 2331 | 2323 | "makeover-layout", | |
| @@ -2334,9 +2326,7 @@ | |||
| 2334 | 2326 | ||
| 2335 | 2327 | [[package]] | |
| 2336 | 2328 | name = "makeover-webview" | |
| 2337 | - | version = "0.35.0" | |
| 2338 | - | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2339 | - | checksum = "115be68562840a2d96630116c0ef745431e608c5c67557f0025fdd7315da73bd" | |
| 2329 | + | version = "0.35.1" | |
| 2340 | 2330 | dependencies = [ | |
| 2341 | 2331 | "makeover-geometry", | |
| 2342 | 2332 | "makeover-layout", | |
| @@ -5514,6 +5504,14 @@ | |||
| 5514 | 5504 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 5515 | 5505 | checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" | |
| 5516 | 5506 | ||
| 5507 | + | [[patch.unused]] | |
| 5508 | + | name = "synckit-client" | |
| 5509 | + | version = "0.8.0" | |
| 5510 | + | ||
| 5511 | + | [[patch.unused]] | |
| 5512 | + | name = "synckit-config" | |
| 5513 | + | version = "0.2.0" | |
| 5514 | + | ||
| 5517 | 5515 | [[patch.unused]] | |
| 5518 | 5516 | name = "kberg" | |
| 5519 | 5517 | version = "0.1.0" | |
| @@ -5529,11 +5527,3 @@ | |||
| 5529 | 5527 | [[patch.unused]] | |
| 5530 | 5528 | name = "tagtree" | |
| 5531 | 5529 | version = "0.4.0" | |
| 5532 | - | ||
| 5533 | - | [[patch.unused]] | |
| 5534 | - | name = "synckit-client" | |
| 5535 | - | version = "0.8.0" | |
| 5536 | - | ||
| 5537 | - | [[patch.unused]] | |
| 5538 | - | name = "synckit-config" | |
| 5539 | - | version = "0.2.0" |
| @@ -13,4 +13,4 @@ | |||
| 13 | 13 | workspace = true | |
| 14 | 14 | ||
| 15 | 15 | [dependencies] | |
| 16 | - | makeover-layout = "0.19.0" | |
| 16 | + | makeover-layout = "0.20.0" |
| @@ -14,13 +14,13 @@ | |||
| 14 | 14 | ||
| 15 | 15 | [dependencies] | |
| 16 | 16 | quasi-router = { path = "../quasi-router", version = "0.2.0" } | |
| 17 | - | makeover-layout = "0.19.0" | |
| 17 | + | makeover-layout = "0.20.0" | |
| 18 | 18 | # The depth palette, the theme bridge and the table. Everything else this crate | |
| 19 | 19 | # draws is written here first and lifted upstream once a second consumer wants | |
| 20 | 20 | # it, which is the order the suite has always moved in: the constrained consumer | |
| 21 | 21 | # finds the shape, and the shared crate takes it after it is known rather than | |
| 22 | 22 | # before. | |
| 23 | - | makeover-tui = { version = "0.18.0", features = ["theme"] } | |
| 23 | + | makeover-tui = { version = "0.19.0", features = ["theme"] } | |
| 24 | 24 | ratatui = { version = "0.30", default-features = false } | |
| 25 | 25 | # `Node::Rich` carries markdown source. A terminal has no markup to hand it to, | |
| 26 | 26 | # so it takes the runs: `render_runs` is the words with the marks that were over |
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | [dependencies] | |
| 16 | 16 | quasi-router = { path = "../quasi-router", version = "0.2.0" } | |
| 17 | 17 | quasi-http = { path = "../quasi-http", version = "0.2.0" } | |
| 18 | - | makeover-layout = "0.19.0" | |
| 18 | + | makeover-layout = "0.20.0" | |
| 19 | 19 | makeover-webview = "0.35.0" | |
| 20 | 20 | # `Node::Rich` carries markdown source and this is what turns it into markup. | |
| 21 | 21 | # Sanitising comes with it, which is why the node can carry what a user typed. |
| @@ -1043,6 +1043,24 @@ | |||
| 1043 | 1043 | /// What the app calls it. Never interpreted here. | |
| 1044 | 1044 | name: String, | |
| 1045 | 1045 | }, | |
| 1046 | + | /// A named assembly of things the description already says. | |
| 1047 | + | /// | |
| 1048 | + | /// The third tier, and the one member that is a name *and* contents. See | |
| 1049 | + | /// [`layout::Region::Widget`] for what separates it from the two either | |
| 1050 | + | /// side of it; the short form is that a primitive has to be drawable by | |
| 1051 | + | /// every host from scratch and a bespoke carries nothing under it, and a | |
| 1052 | + | /// carousel is neither. | |
| 1053 | + | /// | |
| 1054 | + | /// The body is the assembly and it is ordinary description: a renderer that | |
| 1055 | + | /// does not recognise the name walks it and draws primitives, which is why | |
| 1056 | + | /// naming one costs no renderer release. Contrast | |
| 1057 | + | /// [`Bespoke`](Self::Bespoke), whose body a renderer can draw but whose | |
| 1058 | + | /// *fill* only the host has. | |
| 1059 | + | Widget { | |
| 1060 | + | /// What the assembly is called. Never interpreted here, and a renderer | |
| 1061 | + | /// is free not to know it. | |
| 1062 | + | name: String, | |
| 1063 | + | }, | |
| 1046 | 1064 | } | |
| 1047 | 1065 | ||
| 1048 | 1066 | impl RegionKind { | |
| @@ -1057,6 +1075,7 @@ | |||
| 1057 | 1075 | Self::TabGroup => layout::Region::TabGroup, | |
| 1058 | 1076 | Self::Modal => layout::Region::Modal, | |
| 1059 | 1077 | Self::Bespoke { name } => layout::Region::Bespoke { name }, | |
| 1078 | + | Self::Widget { name } => layout::Region::Widget { name }, | |
| 1060 | 1079 | } | |
| 1061 | 1080 | } | |
| 1062 | 1081 | ||
| @@ -1137,6 +1156,17 @@ | |||
| 1137 | 1156 | Self::new(id, RegionKind::Bespoke { name: name.into() }) | |
| 1138 | 1157 | } | |
| 1139 | 1158 | ||
| 1159 | + | /// A named assembly, whose body says what it is made of. | |
| 1160 | + | /// | |
| 1161 | + | /// The body is not optional in spirit, though nothing here enforces it: a | |
| 1162 | + | /// widget with an empty body is a [`bespoke`](Self::bespoke) that has | |
| 1163 | + | /// mislaid its host fill, and a renderer that does not know the name will | |
| 1164 | + | /// draw nothing at all. Assemble it out of members the description already | |
| 1165 | + | /// has, the way [`layout::Region::Widget`] describes. | |
| 1166 | + | pub fn widget(id: impl Into<String>, name: impl Into<String>) -> Self { | |
| 1167 | + | Self::new(id, RegionKind::Widget { name: name.into() }) | |
| 1168 | + | } | |
| 1169 | + | ||
| 1140 | 1170 | /// Add a node, chaining. | |
| 1141 | 1171 | #[must_use] | |
| 1142 | 1172 | pub fn with(mut self, node: Node) -> Self { |
| @@ -62,8 +62,8 @@ | |||
| 62 | 62 | pub use runtime::{Key, Runtime, Step}; | |
| 63 | 63 | pub use view::View; | |
| 64 | 64 | ||
| 65 | + | use makeover_tui::piece::PieceStyle; | |
| 65 | 66 | use makeover_tui::table::TableStyle; | |
| 66 | - | use makeover_tui::widget::WidgetStyle; | |
| 67 | 67 | use makeover_tui::{Fidelity, Palette, Theme}; | |
| 68 | 68 | use quasi_router::{Node, Screen}; | |
| 69 | 69 | use ratatui::buffer::Buffer; | |
| @@ -72,14 +72,14 @@ | |||
| 72 | 72 | /// A terminal renderer for a described screen. | |
| 73 | 73 | /// | |
| 74 | 74 | /// Holds what a drawing needs and no screen state: the theme's colours, the | |
| 75 | - | /// terminal's colour fidelity, and the table and widget styles derived from | |
| 75 | + | /// terminal's colour fidelity, and the table and piece styles derived from | |
| 76 | 76 | /// both. A host makes one and keeps it. | |
| 77 | 77 | #[derive(Debug, Clone)] | |
| 78 | 78 | pub struct Tui { | |
| 79 | 79 | theme: Theme, | |
| 80 | 80 | palette: Palette, | |
| 81 | 81 | table: TableStyle, | |
| 82 | - | widget: WidgetStyle, | |
| 82 | + | piece: PieceStyle, | |
| 83 | 83 | } | |
| 84 | 84 | ||
| 85 | 85 | impl Tui { | |
| @@ -90,7 +90,7 @@ | |||
| 90 | 90 | Self { | |
| 91 | 91 | palette: theme.palette(fidelity), | |
| 92 | 92 | table: TableStyle::from_theme(&theme), | |
| 93 | - | widget: WidgetStyle::from_theme(&theme), | |
| 93 | + | piece: PieceStyle::from_theme(&theme), | |
| 94 | 94 | theme, | |
| 95 | 95 | } | |
| 96 | 96 | } | |
| @@ -170,8 +170,8 @@ | |||
| 170 | 170 | /// ratatui `Style` out — so they went to `makeover-tui` 0.16.0 with the | |
| 171 | 171 | /// drawings that read them, and every terminal app in the tree now says a | |
| 172 | 172 | /// danger tone the same way. | |
| 173 | - | pub(crate) const fn style(&self) -> &WidgetStyle { | |
| 174 | - | &self.widget | |
| 173 | + | pub(crate) const fn style(&self) -> &PieceStyle { | |
| 174 | + | &self.piece | |
| 175 | 175 | } | |
| 176 | 176 | } | |
| 177 | 177 |
| @@ -5,7 +5,7 @@ | |||
| 5 | 5 | //! no way to honour, and each one is a finding rather than an omission. | |
| 6 | 6 | ||
| 7 | 7 | use makeover_layout as layout; | |
| 8 | - | use makeover_tui::{table, text, widget}; | |
| 8 | + | use makeover_tui::{piece, table, text}; | |
| 9 | 9 | use quasi_router::{Act, Cell, Cells, Field, Figure, Meter, Node, Part, Row, Tag}; | |
| 10 | 10 | use ratatui::buffer::Buffer; | |
| 11 | 11 | use ratatui::layout::Rect; | |
| @@ -559,7 +559,7 @@ | |||
| 559 | 559 | /// `makeover-tui`'s answers now. What is left here is the translation: our | |
| 560 | 560 | /// owned [`Tag`] into the parts the shared drawing takes. | |
| 561 | 561 | fn tag_span(tui: &Tui, tag: &Tag, focused: bool) -> Span<'static> { | |
| 562 | - | widget::token( | |
| 562 | + | piece::token( | |
| 563 | 563 | tui.style(), | |
| 564 | 564 | &tag.label, | |
| 565 | 565 | tag.kind, | |
| @@ -576,27 +576,27 @@ | |||
| 576 | 576 | /// show, and a confirmation is a question asked after the press, which is the | |
| 577 | 577 | /// runtime's. [`quasi_router::Act::as_layout`] says the same at the seam. | |
| 578 | 578 | fn act_line(tui: &Tui, act: &Act, focused: bool) -> Line<'static> { | |
| 579 | - | widget::act(tui.style(), &act.as_layout(), focused) | |
| 579 | + | piece::act(tui.style(), &act.as_layout(), focused) | |
| 580 | 580 | } | |
| 581 | 581 | ||
| 582 | 582 | /// A meter as a line, bar and label. | |
| 583 | 583 | fn meter_line(tui: &Tui, meter: &Meter) -> Line<'static> { | |
| 584 | - | widget::meter(tui.style(), &meter.as_layout()) | |
| 584 | + | piece::meter(tui.style(), &meter.as_layout()) | |
| 585 | 585 | } | |
| 586 | 586 | ||
| 587 | 587 | /// A figure takes two rows: the number, then what it counts. | |
| 588 | 588 | fn figure_height(_tui: &Tui, figure: &Figure, width: u16) -> u16 { | |
| 589 | - | widget::figure_height(&figure.as_layout(), width) | |
| 589 | + | piece::figure_height(&figure.as_layout(), width) | |
| 590 | 590 | } | |
| 591 | 591 | ||
| 592 | 592 | fn draw_figure(tui: &Tui, figure: &Figure, area: Rect, buf: &mut Buffer) -> u16 { | |
| 593 | - | widget::figure(tui.style(), &figure.as_layout(), area, buf) | |
| 593 | + | piece::figure(tui.style(), &figure.as_layout(), area, buf) | |
| 594 | 594 | } | |
| 595 | 595 | ||
| 596 | 596 | /// A question takes its label row, its value row, and a row for whatever went | |
| 597 | 597 | /// wrong. | |
| 598 | 598 | fn field_height(tui: &Tui, field: &Field, width: u16) -> u16 { | |
| 599 | - | field.with_layout(|field| widget::field_height(tui.style(), &field, width)) | |
| 599 | + | field.with_layout(|field| piece::field_height(tui.style(), &field, width)) | |
| 600 | 600 | } | |
| 601 | 601 | ||
| 602 | 602 | fn draw_field(pass: &mut Pass<'_>, field: &Field, area: Rect, buf: &mut Buffer) -> u16 { | |
| @@ -620,12 +620,12 @@ | |||
| 620 | 620 | // `Node::SELECTED` is quasi's submission convention and not a fact about | |
| 621 | 621 | // what a tick looks like. | |
| 622 | 622 | let held = if matches!(field.kind, layout::FieldKind::Checkbox) { | |
| 623 | - | widget::Held::On(held == Node::SELECTED) | |
| 623 | + | piece::Held::On(held == Node::SELECTED) | |
| 624 | 624 | } else { | |
| 625 | - | widget::Held::Text(held) | |
| 625 | + | piece::Held::Text(held) | |
| 626 | 626 | }; | |
| 627 | 627 | ||
| 628 | - | field.with_layout(|described| widget::field(tui.style(), &described, held, focused, area, buf)) | |
| 628 | + | field.with_layout(|described| piece::field(tui.style(), &described, held, focused, area, buf)) | |
| 629 | 629 | } | |
| 630 | 630 | ||
| 631 | 631 | /// A tabs strip, a segmented control and a toggle, all as one row of labels. |
| @@ -1365,6 +1365,7 @@ | |||
| 1365 | 1365 | quasi_router::RegionKind::TabGroup => "tabgroup", | |
| 1366 | 1366 | quasi_router::RegionKind::Modal => "modal", | |
| 1367 | 1367 | quasi_router::RegionKind::Bespoke { .. } => "bespoke", | |
| 1368 | + | quasi_router::RegionKind::Widget { .. } => "widget", | |
| 1368 | 1369 | }; | |
| 1369 | 1370 | ||
| 1370 | 1371 | out.push_str("<div id=\""); | |
| @@ -1383,6 +1384,23 @@ | |||
| 1383 | 1384 | out.push('"'); | |
| 1384 | 1385 | } | |
| 1385 | 1386 | ||
| 1387 | + | if let quasi_router::RegionKind::Widget { name } = &slot.kind { | |
| 1388 | + | // Also never interpreted here, and for a different purpose: this is the | |
| 1389 | + | // hook a stylesheet or a script attaches to in order to draw the | |
| 1390 | + | // assembly the way a browser does it. It is an attribute rather than a | |
| 1391 | + | // class because a widget name is app vocabulary and classes here are | |
| 1392 | + | // this renderer's. | |
| 1393 | + | // | |
| 1394 | + | // What makes it safe to emit and ignore is that the body under it is | |
| 1395 | + | // already the whole assembly in primitives. Nothing recognises | |
| 1396 | + | // `data-widget` and the region still renders -- a carousel degrades to | |
| 1397 | + | // its frames, which is the JS-off fallback the shipped partial has and | |
| 1398 | + | // the reason the tier does not need three renderers to release in step. | |
| 1399 | + | out.push_str(" data-widget=\""); | |
| 1400 | + | out.push_str(&escape(name)); | |
| 1401 | + | out.push('"'); | |
| 1402 | + | } | |
| 1403 | + | ||
| 1386 | 1404 | if matches!(slot.readiness, layout::Readiness::Pending) { | |
| 1387 | 1405 | out.push_str(" aria-busy=\"true\""); | |
| 1388 | 1406 | } |