╭ changed ────────╮ │src/main_wasm.zig│ ╰─────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────╮ │ 1 const std = @import("std"); │ │ 2 const ui = @import("./ui.zig"); │ │ 3 const web = @import("./web.zig"); │ │ 4 -const xitui = @import("xit").xitui; │ │ 4 +const xit = @import("xit"); │ │ 5 +const xitui = xit.xitui; │ │ 6 const inp = xitui.input; │ │ 7 +const wgt = xitui.widget; │ │ 8 │ │ 9 const allocator = std.heap.wasm_allocator;│ │10 │ ╰──────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │12 │ │13 fn updateHtml() !void { │ │14 const root_ptr = if (root) |*root_value| root_value else return error.NotStarted;│ │13 - const html = try web.generateHtml(allocator, root_ptr); │ │15 + const html = try web.generateHtml(allocator, root_ptr, &session); │ │16 defer allocator.free(html); │ │17 setHtml(html); │ │18 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │21 // to outlive `root`, because `root` holds slices into the parsed strings.│ │22 var page_arena: ?std.heap.ArenaAllocator = null; │ │23 var page: ?ui.Page = null; │ │24 +var session: ui.Session = .{}; │ │25 │ │26 fn start(json: []const u8, max_width: u32) !void { │ │27 if (page_arena) |*a| a.deinit(); │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │33 .allocate = .alloc_always, │ │34 }); │ │35 │ │33 - var next_root = try ui.initRoot(allocator, &(page orelse unreachable)); │ │36 + // restore session.user_id from the serialized page so the first render │ │37 + // matches what the server rendered (otherwise wasm would render the │ │38 + // page in a logged-out state on top of a logged-in server-rendered HTML). │ │39 + session.user_id = switch (page orelse unreachable) { │ │40 + .home => |h| h.user_id, │ │41 + }; │ │42 + │ │43 + var next_root = try ui.initRoot(allocator, &(page orelse unreachable), &session);│ │44 errdefer next_root.deinit(); │ │45 │ │46 if (root) |*old_root| old_root.deinit(); │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │63 fn onKeyDown(key_code: u32) !void { │ │64 const root_ptr = if (root) |*root_value| root_value else return error.NotStarted;│ │65 const key: inp.Key = switch (key_code) { │ │66 + 13 => .enter, │ │67 33 => .page_up, │ │68 34 => .page_down, │ │69 35 => .end, │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │135 }; │ │136 } │ │137 │ │138 +// js calls this when the value of an overlay <input> changes; we replace │ │139 +// the matching TextInput's content with the supplied utf-8 bytes. │ │140 +export fn _setTextInputValue(focus_id: u32, value_ptr: [*]const u8, value_len: u32) void { │ │141 + setTextInputValue(focus_id, value_ptr[0..value_len]) catch |err| { │ │142 + var buf: [256]u8 = undefined; │ │143 + const str = std.fmt.bufPrint(&buf, "setTextInputValue: {}", .{err}) catch unreachable;│ │144 + consoleLog(str); │ │145 + }; │ │146 +} │ │147 + │ │148 +fn setTextInputValue(focus_id: u32, bytes: []const u8) !void { │ │149 + const root_ptr = if (root) |*r| r else return error.NotStarted; │ │150 + const root_focus = root_ptr.getFocus(); │ │151 + const child = root_focus.children.get(focus_id) orelse return error.UnknownFocusId; │ │152 + switch (child.focus.kind) { │ │153 + .text_input, .text_input_password => {}, │ │154 + else => return error.NotATextInput, │ │155 + } │ │156 + const ti: *wgt.TextInput(ui.Widget) = @fieldParentPtr("focus", child.focus); │ │157 + try ti.setContent(bytes); │ │158 +} │ │159 + │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯