fix: unescaping in client side rendering

This commit is contained in:
Nurul Huda (Apon) 2026-06-13 04:50:53 +06:00
parent d7c195555f
commit a90ae7c6bb
No known key found for this signature in database
GPG Key ID: 5D3F1DE2855A2F79
3 changed files with 27 additions and 0 deletions

View File

@ -310,6 +310,10 @@ export class ZxBridge extends ZxBridgeCore {
const node = domNodes.get(vnodeId);
if (node) node.nodeValue = readString(ptr, len);
},
_srh: (vnodeId: bigint, ptr: number, len: number) => {
const el = domNodes.get(vnodeId) as Element | undefined;
if (el) el.innerHTML = readString(ptr, len);
},
_ac: (parentId: bigint, childId: bigint) => {
const parent = domNodes.get(parentId);
const child = domNodes.get(childId);

View File

@ -277,6 +277,25 @@ pub fn createPlatformNodes(allocator: zx.Allocator, vnode: *VNode, client: anyty
}
}
// When escaping is disabled (@escaping={.none}), the element's text
// children are raw HTML and must be inserted via innerHTML
if (elem.escaping == .none) {
var aw = std.Io.Writer.Allocating.init(allocator);
defer aw.deinit();
for (vnode.children.items) |child| {
const resolved_child = try vdom.resolveComponent(allocator, child.component, child.owner_component_id, 0);
switch (resolved_child) {
.text => |t| try aw.writer.writeAll(t),
.none => {},
// Non-text children fall back to normal node creation below.
else => {},
}
}
const raw = aw.written();
ext._srh(vnode.id, raw.ptr, raw.len);
break :blk .{ .element = htmlElementFromRef(allocator, ref_id) };
}
for (vnode.children.items) |child| {
_ = try createPlatformNodes(allocator, child, client, options);
ext._ac(vnode.id, child.id);

View File

@ -23,6 +23,10 @@ pub extern "__zx" fn _ra(vnode_id: u64, name_ptr: [*]const u8, name_len: usize)
/// Set nodeValue on the text node identified by vnode_id.
pub extern "__zx" fn _snv(vnode_id: u64, ptr: [*]const u8, len: usize) void;
/// Set innerHTML (raw, unescaped HTML) on the element identified by vnode_id.
/// Used for elements with @escaping={.none}.
pub extern "__zx" fn _srh(vnode_id: u64, ptr: [*]const u8, len: usize) void;
// DOM tree mutation
/// parent.appendChild(child) - both nodes looked up by vnode_id.