From 99c4702676053808b8621aec20d27b8f0815e627 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Sat, 3 Oct 2026 22:26:54 -0700 Subject: [PATCH] fix: preserve browser accessibility identities and disabled states Carry 64-bit AccessKit node IDs as decimal strings across the JavaScript bridge so clicks return to the original node. Use explicit true/false values for aria-disabled. Assisted-by: gpt-6.1-sol --- crates/snowbound/src/web.rs | 19 +++++++++---------- crates/snowbound/web/glue.js | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/snowbound/src/web.rs b/crates/snowbound/src/web.rs index 5059f960b922776c8710d60f85b09c8dc31abb2a..456fe5a3828b528ad1c7ca96787433e2dd36bb0a 100644 --- a/crates/snowbound/src/web.rs +++ b/crates/snowbound/src/web.rs @@ -428,7 +428,7 @@ fn mirrored(update: &accesskit::TreeUpdate) -> js_sys::Object { let children: js_sys::Array = node .children() .iter() - .map(|child| JsValue::from_f64(child.0 as f64)) + .map(|child| JsValue::from_str(&child.0.to_string())) .collect(); let bounds = node.bounds().map_or(JsValue::NULL, |rect| { js_sys::Array::of4( @@ -441,7 +441,7 @@ fn mirrored(update: &accesskit::TreeUpdate) -> js_sys::Object { }); let text = |text: Option<&str>| text.map_or(JsValue::NULL, JsValue::from_str); [ - JsValue::from_f64(id.0 as f64), + JsValue::from_str(&id.0.to_string()), JsValue::from_str(&format!("{:?}", node.role())), text(node.label()), text(node.value()), @@ -462,13 +462,12 @@ fn mirrored(update: &accesskit::TreeUpdate) -> js_sys::Object { let _ = js_sys::Reflect::set(&mirrored, &key.into(), value); }; set("tree", &tree(update.tree_id)); - set("focus", &JsValue::from_f64(update.focus.0 as f64)); + set("focus", &JsValue::from_str(&update.focus.0.to_string())); set( "root", - &update - .tree - .as_ref() - .map_or(JsValue::NULL, |info| JsValue::from_f64(info.root.0 as f64)), + &update.tree.as_ref().map_or(JsValue::NULL, |info| { + JsValue::from_str(&info.root.0.to_string()) + }), ); set("nodes", &nodes); mirrored @@ -486,8 +485,8 @@ pub fn accessibility(on: bool) { /// Assistive technology acted on node `node` of tree `tree`: 0 clicks it, 1 focuses it. #[wasm_bindgen] -pub fn access(tree: String, node: f64, action: u8) { - let Ok(tree) = tree.parse() else { +pub fn access(tree: String, node: String, action: u8) { + let (Ok(tree), Ok(node)) = (tree.parse(), node.parse()) else { return; }; let request = accesskit::ActionRequest { @@ -496,7 +495,7 @@ pub fn access(tree: String, node: f64, action: u8) { _ => accesskit::Action::Click, }, target_tree: accesskit::TreeId(tree), - target_node: accesskit::NodeId(node as u64), + target_node: accesskit::NodeId(node), data: None, }; send(UserEvent::Then(Box::new(move |state| { diff --git a/crates/snowbound/web/glue.js b/crates/snowbound/web/glue.js index 3eb7d41f542a210f5f63038fc0396809893a3696..f2fcaed42091a5257cb9317dddc4d63fce3af68d 100644 --- a/crates/snowbound/web/glue.js +++ b/crates/snowbound/web/glue.js @@ -564,7 +564,7 @@ export function mirrorTree({ tree, focus, root, nodes }) { const text = role === "Label" || role === "TextRun" || role === "StaticText"; if (name && !text) node.setAttribute("aria-label", name); else node.removeAttribute("aria-label"); - node.toggleAttribute("aria-disabled", disabled); + node.setAttribute("aria-disabled", String(disabled)); if (toggled === null) node.removeAttribute("aria-checked"); else node.setAttribute("aria-checked", String(toggled)); const kids = children.map(element); -- 2.54.0