╭ changed ────╮ │build.zig.zon│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 3 .version = "0.0.0", │ │ 4 .dependencies = .{ │ │ 5 .xit = .{ │ │ 6 - .url = "git+https://github.com/xit-vcs/xit#cf2786c37c523f0b00f8f655a71f67e725147472",│ │ 7 - .hash = "xit-0.0.0-Ub3nDAa5UAFA66Lrft_o8Tivhw2zs_OiCSVvDvAwfuVm", │ │ 6 + .url = "git+https://github.com/xit-vcs/xit#4ea5a2aa70b64fe8aba4a0b0e246bd24642bfe7b",│ │ 7 + .hash = "xit-0.0.0-Ub3nDGSxUAHkV15jDN8pisWuDXjI4w8xm6D2aKEParqP", │ │ 8 }, │ │ 9 }, │ │10 .paths = .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────╮ │src/embed/index.html│ ╰────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │33 position: relative; │ │34 } │ │35 │ │36 - body:has(#grid .scroll) { │ │36 + body:has(#grid .scroll:not([data-scroll-direction="horiz"])) {│ │37 height: 100vh; │ │38 overflow: hidden; │ │39 } │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────╮ │src/embed/script.js│ ╰───────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │183 const top = first.top - c.top + container.scrollTop; │ │184 const bottom = last.bottom - c.top + container.scrollTop; │ │185 const left = first.left - c.left + container.scrollLeft; │ │186 + let right = left; │ │187 + for (const el of els) { │ │188 + right = Math.max(right, el.getBoundingClientRect().right - c.left + container.scrollLeft);│ │189 + } │ │190 │ │191 // vertical is the priority axis. keep the viewport in place when it │ │192 // already overlaps a tall widget; otherwise reveal its nearest edge. │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │197 } else if (bottom > container.scrollTop + container.clientHeight) { │ │198 container.scrollTop = bottom - container.clientHeight; │ │199 } │ │196 - // horizontal: only reveal the row's start, never chase the right edge, │ │197 - // so moving down through varying-width rows doesn't yank the view │ │198 - // sideways. (a hidden-overflow x axis stays at 0, so this no-ops.) │ │199 - if (left < container.scrollLeft) container.scrollLeft = left; │ │200 + // horizontal-only scrolls are rows of controls, so reveal either │ │201 + // edge. other scrolls reveal only the row's start; chasing varying │ │202 + // right edges while moving vertically would yank their view sideways. │ │203 + if (left < container.scrollLeft) { │ │204 + container.scrollLeft = left; │ │205 + } else if (container.dataset.scrollDirection === "horiz" && right > container.scrollLeft + container.clientWidth) {│ │206 + container.scrollLeft = right - container.clientWidth; │ │207 + } │ │208 }, │ │209 }, │ │210 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Home/Header.zig│ ╰──────────────────────╯ ╭────────────────────────────────────────────────────────────╮ │24 } │ │25 │ │26 pub const View = struct { │ │27 - box: wgt.Box(ui.Widget), │ │27 + scroll: wgt.Scroll(ui.Widget), │ │28 data: *const Self, │ │29 tab_ids: std.AutoArrayHashMapUnmanaged(usize, void),│ │30 │ ╰────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────╮ │44 .widget = .{ .title = title_view },│ │45 .rect = null, │ │46 .min_size = null, │ │47 - .shrink = true, │ │47 + .flex = .shrink, │ │48 }); │ │49 } │ │50 │ ╰───────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────╮ │107 .widget = .{ .spacer = spacer },│ │108 .rect = null, │ │109 .min_size = null, │ │110 + .flex = .grow, │ │111 }); │ │112 } │ │113 │ ╰─────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │154 }); │ │155 } │ │156 │ │156 - var self = View{ .box = box, .data = data, .tab_ids = tab_ids }; │ │157 + var self = View{ │ │158 + .scroll = try wgt.Scroll(ui.Widget).init(allocator, .{ .box = box }, .{ .direction = .horiz, .show_bar = false, .web_native = !session.is_terminal }),│ │159 + .data = data, │ │160 + .tab_ids = tab_ids, │ │161 + }; │ │162 self.getFocus().child_id = selected_tab orelse self.tab_ids.keys()[0]; │ │163 return self; │ │164 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────╮ │165 │ │166 pub fn deinit(self: *View, allocator: std.mem.Allocator) void {│ │162 - self.box.deinit(allocator); │ │167 + self.scroll.deinit(allocator); │ │168 self.tab_ids.deinit(allocator); │ │169 } │ │170 │ ╰────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │171 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void {│ │172 self.clearGrid(); │ │168 - for (self.box.children.keys(), self.box.children.values()) |id, *child| { │ │173 + const box = &self.scroll.child.box; │ │174 + for (box.children.keys(), box.children.values()) |id, *child| { │ │175 const tb: ?*wgt.TextBox(ui.Widget) = switch (child.widget) { │ │176 .text_box => |*x| x, │ │177 .auth_tab => |*at| blk: { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯