diff --git a/packages/html/src/events/animation.rs b/packages/html/src/events/animation.rs index 23f6219121..173127bf9d 100644 --- a/packages/html/src/events/animation.rs +++ b/packages/html/src/events/animation.rs @@ -36,6 +36,12 @@ impl AnimationData { } } +impl Default for AnimationData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for AnimationData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/clipboard.rs b/packages/html/src/events/clipboard.rs index 265a747e9a..c133db868a 100644 --- a/packages/html/src/events/clipboard.rs +++ b/packages/html/src/events/clipboard.rs @@ -6,6 +6,12 @@ pub struct ClipboardData { inner: Box, } +impl Default for ClipboardData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for ClipboardData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/composition.rs b/packages/html/src/events/composition.rs index 4d161436ed..790459e536 100644 --- a/packages/html/src/events/composition.rs +++ b/packages/html/src/events/composition.rs @@ -14,6 +14,12 @@ impl std::fmt::Debug for CompositionData { } } +impl Default for CompositionData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for CompositionData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/drag.rs b/packages/html/src/events/drag.rs index 26f2ebe998..c4be2835f4 100644 --- a/packages/html/src/events/drag.rs +++ b/packages/html/src/events/drag.rs @@ -17,6 +17,12 @@ pub struct DragData { inner: Box, } +impl Default for DragData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for DragData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/focus.rs b/packages/html/src/events/focus.rs index c5571e7ffd..e5a2fb2799 100644 --- a/packages/html/src/events/focus.rs +++ b/packages/html/src/events/focus.rs @@ -6,6 +6,12 @@ pub struct FocusData { inner: Box, } +impl Default for FocusData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for FocusData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/keyboard.rs b/packages/html/src/events/keyboard.rs index 103e1e2953..a96feced85 100644 --- a/packages/html/src/events/keyboard.rs +++ b/packages/html/src/events/keyboard.rs @@ -19,6 +19,12 @@ pub struct KeyboardData { inner: Box, } +impl Default for KeyboardData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for KeyboardData { fn from(e: E) -> Self { Self { inner: Box::new(e) } @@ -105,9 +111,13 @@ pub struct SerializedKeyboardData { key_code: KeyCode, #[serde(deserialize_with = "resilient_deserialize_code")] code: Code, + #[serde(default)] alt_key: bool, + #[serde(default)] ctrl_key: bool, + #[serde(default)] meta_key: bool, + #[serde(default)] shift_key: bool, location: usize, repeat: bool, diff --git a/packages/html/src/events/mod.rs b/packages/html/src/events/mod.rs index d760452609..3002532e88 100644 --- a/packages/html/src/events/mod.rs +++ b/packages/html/src/events/mod.rs @@ -275,6 +275,210 @@ impl From<&PlatformEventData> for WheelData { } } +pub(crate) mod empty { + use crate::{ + geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint, WheelDelta}, + input_data::{MouseButton, MouseButtonSet}, + keyboard_types::{Code, Key, Location, Modifiers}, + HasDragData, HasFileData, HasFocusData, HasKeyboardData, HasMouseData, HasPointerData, + HasTouchData, HasWheelData, InteractionElementOffset, InteractionLocation, + ModifiersInteraction, PointerInteraction, TouchPoint, + }; + + #[derive(Debug, Clone, PartialEq)] + pub(crate) struct EmptyEvent; + + impl HasDragData for EmptyEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl HasFileData for EmptyEvent { + fn files(&self) -> Option> { + None + } + } + impl HasMouseData for EmptyEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl HasPointerData for EmptyEvent { + fn pointer_id(&self) -> i32 { + 0 + } + + fn width(&self) -> i32 { + 0 + } + + fn height(&self) -> i32 { + 0 + } + + fn pressure(&self) -> f32 { + 0.0 + } + + fn tangential_pressure(&self) -> f32 { + 0.0 + } + + fn tilt_x(&self) -> i32 { + 0 + } + + fn tilt_y(&self) -> i32 { + 0 + } + + fn twist(&self) -> i32 { + 0 + } + + fn pointer_type(&self) -> String { + "mouse".to_string() + } + + fn is_primary(&self) -> bool { + false + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl HasTouchData for EmptyEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn touches_changed(&self) -> Vec { + Vec::new() + } + + fn target_touches(&self) -> Vec { + Vec::new() + } + + fn touches(&self) -> Vec { + Vec::new() + } + } + impl HasWheelData for EmptyEvent { + fn delta(&self) -> WheelDelta { + WheelDelta::lines(0.0, 0.0, 0.0) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl super::animation::HasAnimationData for EmptyEvent { + fn animation_name(&self) -> String { + String::new() + } + fn pseudo_element(&self) -> String { + String::new() + } + fn elapsed_time(&self) -> f32 { + 0.0 + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl super::clipboard::HasClipboardData for EmptyEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl super::composition::HasCompositionData for EmptyEvent { + fn data(&self) -> String { + String::new() + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl super::transition::HasTransitionData for EmptyEvent { + fn property_name(&self) -> String { + String::new() + } + fn pseudo_element(&self) -> String { + String::new() + } + fn elapsed_time(&self) -> f32 { + 0.0 + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl HasKeyboardData for EmptyEvent { + fn key(&self) -> Key { + Key::Unidentified + } + + fn code(&self) -> Code { + Code::Unidentified + } + + fn location(&self) -> Location { + Location::Standard + } + + fn is_auto_repeating(&self) -> bool { + false + } + + fn is_composing(&self) -> bool { + false + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl HasFocusData for EmptyEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + impl InteractionLocation for EmptyEvent { + fn client_coordinates(&self) -> ClientPoint { + Default::default() + } + + fn page_coordinates(&self) -> PagePoint { + Default::default() + } + + fn screen_coordinates(&self) -> ScreenPoint { + Default::default() + } + } + impl InteractionElementOffset for EmptyEvent { + fn element_coordinates(&self) -> ElementPoint { + Default::default() + } + } + impl ModifiersInteraction for EmptyEvent { + fn modifiers(&self) -> Modifiers { + Modifiers::empty() + } + } + impl PointerInteraction for EmptyEvent { + fn held_buttons(&self) -> MouseButtonSet { + Default::default() + } + + fn trigger_button(&self) -> Option { + None + } + } +} + mod animation; mod clipboard; mod composition; diff --git a/packages/html/src/events/mouse.rs b/packages/html/src/events/mouse.rs index 4ed8acff6b..ed016c3352 100644 --- a/packages/html/src/events/mouse.rs +++ b/packages/html/src/events/mouse.rs @@ -12,6 +12,12 @@ pub struct MouseData { inner: Box, } +impl Default for MouseData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for MouseData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/pointer.rs b/packages/html/src/events/pointer.rs index d6ce3602a4..19440ca999 100644 --- a/packages/html/src/events/pointer.rs +++ b/packages/html/src/events/pointer.rs @@ -23,6 +23,12 @@ impl PointerData { } } +impl Default for PointerData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for PointerData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/touch.rs b/packages/html/src/events/touch.rs index f6ed287986..1913901db2 100644 --- a/packages/html/src/events/touch.rs +++ b/packages/html/src/events/touch.rs @@ -9,6 +9,12 @@ pub struct TouchData { inner: Box, } +impl Default for TouchData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for TouchData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/transition.rs b/packages/html/src/events/transition.rs index 18863318dd..49aade355a 100644 --- a/packages/html/src/events/transition.rs +++ b/packages/html/src/events/transition.rs @@ -6,6 +6,12 @@ pub struct TransitionData { inner: Box, } +impl Default for TransitionData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for TransitionData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/events/wheel.rs b/packages/html/src/events/wheel.rs index 4beda89566..29d34a34fc 100644 --- a/packages/html/src/events/wheel.rs +++ b/packages/html/src/events/wheel.rs @@ -19,6 +19,12 @@ pub struct WheelData { inner: Box, } +impl Default for WheelData { + fn default() -> Self { + Self::new(crate::events::empty::EmptyEvent) + } +} + impl From for WheelData { fn from(e: E) -> Self { Self { inner: Box::new(e) } diff --git a/packages/html/src/point_interaction.rs b/packages/html/src/point_interaction.rs index b0e34f7809..ffff77d1ae 100644 --- a/packages/html/src/point_interaction.rs +++ b/packages/html/src/point_interaction.rs @@ -51,6 +51,7 @@ pub trait ModifiersInteraction { #[cfg(feature = "serialize")] #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Default)] pub struct SerializedPointInteraction { + #[serde(default)] pub alt_key: bool, /// The button number that was pressed (if applicable) when the mouse event was fired. @@ -78,9 +79,11 @@ pub struct SerializedPointInteraction { pub client_y: i32, /// True if the control key was down when the mouse event was fired. + #[serde(default)] pub ctrl_key: bool, /// True if the meta key was down when the mouse event was fired. + #[serde(default)] pub meta_key: bool, /// The offset in the X coordinate of the mouse pointer between that event and the padding edge of the target node. @@ -106,6 +109,7 @@ pub struct SerializedPointInteraction { pub screen_y: i32, /// True if the shift key was down when the mouse event was fired. + #[serde(default)] pub shift_key: bool, } diff --git a/packages/interpreter/src/js/hash.txt b/packages/interpreter/src/js/hash.txt index 407f37e412..6c7f9fada9 100644 --- a/packages/interpreter/src/js/hash.txt +++ b/packages/interpreter/src/js/hash.txt @@ -1 +1 @@ -[6449103750905854967, 17669692872757955279, 13069001215487072322, 11420464406527728232, 3770103091118609057, 5444526391971481782, 14692042304579321130, 5052021921702764563, 7041565893588933645, 11339769846046015954] \ No newline at end of file +[6449103750905854967, 17669692872757955279, 13069001215487072322, 11420464406527728232, 3770103091118609057, 5444526391971481782, 14692042304579321130, 5052021921702764563, 11363853276787808729, 11339769846046015954] \ No newline at end of file diff --git a/packages/interpreter/src/js/native.js b/packages/interpreter/src/js/native.js index f08b6f0066..f315a356bf 100644 --- a/packages/interpreter/src/js/native.js +++ b/packages/interpreter/src/js/native.js @@ -1 +1 @@ -function retrieveValues(event,target){let contents={values:{}},form=target.closest("form");if(form){if(event.type==="input"||event.type==="change"||event.type==="submit"||event.type==="reset"||event.type==="click")contents=retrieveFormValues(form)}return contents}function retrieveFormValues(form){let formData=new FormData(form),contents={};return formData.forEach((value,key)=>{if(contents[key])contents[key].push(value);else contents[key]=[value]}),{valid:form.checkValidity(),values:contents}}function retrieveSelectValue(target){let options=target.selectedOptions,values=[];for(let i=0;icontents={...contents,...obj};if(event instanceof WheelEvent)extend(serializeWheelEvent(event));if(event instanceof MouseEvent)extend(serializeMouseEvent(event));if(event instanceof KeyboardEvent)extend(serializeKeyboardEvent(event));if(event instanceof InputEvent)extend(serializeInputEvent(event,target));if(event instanceof PointerEvent)extend(serializePointerEvent(event));if(event instanceof AnimationEvent)extend(serializeAnimationEvent(event));if(event instanceof TransitionEvent)extend({property_name:event.propertyName,elapsed_time:event.elapsedTime,pseudo_element:event.pseudoElement});if(event instanceof CompositionEvent)extend({data:event.data});if(event instanceof DragEvent)extend(serializeDragEvent(event));if(event instanceof FocusEvent)extend({});if(event instanceof ClipboardEvent)extend({});if(event instanceof CustomEvent){let detail=event.detail;if(detail instanceof ResizeObserverEntry)extend(serializeResizeEventDetail(detail));else if(detail instanceof IntersectionObserverEntry)extend(serializeIntersectionEventDetail(detail))}if(typeof TouchEvent!=="undefined"&&event instanceof TouchEvent)extend(serializeTouchEvent(event));if(event.type==="submit"||event.type==="reset"||event.type==="click"||event.type==="change"||event.type==="input")extend(serializeInputEvent(event,target));if(event instanceof DragEvent);if(event.type==="scroll")extend(serializeScrollEvent(event));return contents}function toSerializableResizeObserverSize(size,is_inline_width){return[is_inline_width?size.inlineSize:size.blockSize,is_inline_width?size.blockSize:size.inlineSize]}function serializeResizeEventDetail(detail){let is_inline_width=!0;if(detail.target instanceof HTMLElement){if(window.getComputedStyle(detail.target).getPropertyValue("writing-mode")!=="horizontal-tb")is_inline_width=!1}return{border_box_size:detail.borderBoxSize!==void 0?toSerializableResizeObserverSize(detail.borderBoxSize[0],is_inline_width):detail.contentRect,content_box_size:detail.contentBoxSize!==void 0?toSerializableResizeObserverSize(detail.contentBoxSize[0],is_inline_width):detail.contentRect,content_rect:detail.contentRect}}function serializeIntersectionEventDetail(detail){return{bounding_client_rect:detail.boundingClientRect,intersection_ratio:detail.intersectionRatio,intersection_rect:detail.intersectionRect,is_intersecting:detail.isIntersecting,root_bounds:detail.rootBounds,time_ms:Math.floor(Date.now()+detail.time)}}function serializeInputEvent(event,target){let contents={};if(target instanceof HTMLElement){let values=retrieveValues(event,target);contents.values=values.values,contents.valid=values.valid}if(event.target instanceof HTMLInputElement){let target2=event.target,value=target2.value??target2.textContent??"";if(target2.type==="checkbox")value=target2.checked?"true":"false";else if(target2.type==="radio")value=target2.value;contents.value=value}if(event.target instanceof HTMLTextAreaElement)contents.value=event.target.value;if(event.target instanceof HTMLSelectElement)contents.value=retrieveSelectValue(event.target).join(",");if(contents.value===void 0)contents.value="";return contents}function serializeWheelEvent(event){return{delta_x:event.deltaX,delta_y:event.deltaY,delta_z:event.deltaZ,delta_mode:event.deltaMode}}function serializeTouchEvent(event){return{alt_key:event.altKey,ctrl_key:event.ctrlKey,meta_key:event.metaKey,shift_key:event.shiftKey,changed_touches:serializeTouchList(event.changedTouches),target_touches:serializeTouchList(event.targetTouches),touches:serializeTouchList(event.touches)}}function serializePointerEvent(event){return{alt_key:event.altKey,button:event.button,buttons:event.buttons,client_x:event.clientX,client_y:event.clientY,ctrl_key:event.ctrlKey,meta_key:event.metaKey,page_x:event.pageX,page_y:event.pageY,screen_x:event.screenX,screen_y:event.screenY,shift_key:event.shiftKey,pointer_id:event.pointerId,width:event.width,height:event.height,pressure:event.pressure,tangential_pressure:event.tangentialPressure,tilt_x:event.tiltX,tilt_y:event.tiltY,twist:event.twist,pointer_type:event.pointerType,is_primary:event.isPrimary}}function serializeTouchList(touchList){let serializedTouches=[];for(let i=0;i0)files={files:{placeholder:[]}};return{mouse:{alt_key:event.altKey,ctrl_key:event.ctrlKey,meta_key:event.metaKey,shift_key:event.shiftKey,...serializeMouseEvent(event)},files}}function serializeScrollEvent(event){let scrollLeft=0,scrollTop=0,scrollWidth=0,scrollHeight=0,clientWidth=0,clientHeight=0;if(event.target instanceof Element)scrollLeft=event.target.scrollLeft,scrollTop=event.target.scrollTop,scrollWidth=event.target.scrollWidth,scrollHeight=event.target.scrollHeight,clientWidth=event.target.clientWidth,clientHeight=event.target.clientHeight;else if(event.target===document)scrollLeft=window.scrollX||document.documentElement.scrollLeft,scrollTop=window.scrollY||document.documentElement.scrollTop,scrollWidth=document.documentElement.scrollWidth,scrollHeight=document.documentElement.scrollHeight,clientWidth=document.documentElement.clientWidth,clientHeight=document.documentElement.clientHeight;return{scroll_left:scrollLeft,scroll_top:scrollTop,scroll_width:scrollWidth,scroll_height:scrollHeight,client_width:clientWidth,client_height:clientHeight}}var JSChannel_;if(RawInterpreter!==void 0&&RawInterpreter!==null)JSChannel_=RawInterpreter;class NativeInterpreter extends JSChannel_{intercept_link_redirects;ipc;edits;eventsPath;headless;kickStylesheets;queuedBytes=[];liveview;constructor(eventsPath,headless){super();this.eventsPath=eventsPath,this.kickStylesheets=!1,this.headless=headless}initialize(root){this.intercept_link_redirects=!0,this.liveview=!1,window.addEventListener("dragover",function(e){if(e.target instanceof Element&&e.target.tagName!="INPUT")e.preventDefault()},!1),window.addEventListener("drop",function(e){if(!(e.target instanceof Element))return;e.preventDefault()},!1),window.addEventListener("click",(event)=>{let target=event.target;if(target instanceof HTMLInputElement&&target.getAttribute("type")==="file"){let target_id=getTargetId(target);if(target_id!==null){let message=this.serializeIpcMessage("file_dialog",{event:"change&input",accept:target.getAttribute("accept"),directory:target.getAttribute("webkitdirectory")==="true",multiple:target.hasAttribute("multiple"),target:target_id,bubbles:event.bubbles});this.ipc.postMessage(message),event.preventDefault()}}}),this.ipc=window.ipc;let handler=(event)=>this.handleEvent(event,event.type,!0);super.initialize(root,handler)}serializeIpcMessage(method,params={}){return JSON.stringify({method,params})}scrollTo(id,options){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollIntoView(options),!0;return!1}scroll(id,x,y,behavior){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scroll({top:y,left:x,behavior}),!0;return!1}getScrollHeight(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollHeight}getScrollLeft(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollLeft}getScrollTop(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollTop}getScrollWidth(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollWidth}getClientRect(id){let node=this.nodes[id];if(node instanceof HTMLElement){let rect=node.getBoundingClientRect();return{type:"GetClientRect",origin:[rect.x,rect.y],size:[rect.width,rect.height]}}}setFocus(id,focus){let node=this.nodes[id];if(node instanceof HTMLElement)if(focus)node.focus();else node.blur()}handleWindowsDragDrop(){if(window.dxDragLastElement){let dragLeaveEvent=new DragEvent("dragleave",{bubbles:!0,cancelable:!0});window.dxDragLastElement.dispatchEvent(dragLeaveEvent);let data=new DataTransfer,file=new File(["content"],"file.txt",{type:"text/plain"});data.items.add(file);let dragDropEvent=new DragEvent("drop",{bubbles:!0,cancelable:!0,dataTransfer:data});window.dxDragLastElement.dispatchEvent(dragDropEvent),window.dxDragLastElement=null}}handleWindowsDragOver(xPos,yPos){let displayScaleFactor=window.devicePixelRatio||1;xPos/=displayScaleFactor,yPos/=displayScaleFactor;let element=document.elementFromPoint(xPos,yPos);if(element!=window.dxDragLastElement){if(window.dxDragLastElement){let dragLeaveEvent=new DragEvent("dragleave",{bubbles:!0,cancelable:!0});window.dxDragLastElement.dispatchEvent(dragLeaveEvent)}let dragOverEvent=new DragEvent("dragover",{bubbles:!0,cancelable:!0});element.dispatchEvent(dragOverEvent),window.dxDragLastElement=element}}handleWindowsDragLeave(){if(window.dxDragLastElement){let dragLeaveEvent=new DragEvent("dragleave",{bubbles:!0,cancelable:!0});window.dxDragLastElement.dispatchEvent(dragLeaveEvent),window.dxDragLastElement=null}}loadChild(array){let node=this.stack[this.stack.length-1];for(let i=0;i0;end--)node=node.nextSibling}return node}appendChildren(id,many){let root=this.nodes[id],els=this.stack.splice(this.stack.length-many);for(let k=0;k{this.flushQueuedBytes(),this.markEditsFinished()})}waitForRequest(editsPath,required_server_key){this.edits=new WebSocket(editsPath);let authenticated=!1;this.edits.onclose=()=>{setTimeout(()=>{if(this.edits.url!=editsPath)return;this.waitForRequest(editsPath,required_server_key)},100)},this.edits.onmessage=(event)=>{let data=event.data;if(data instanceof Blob){if(!authenticated)return;data.arrayBuffer().then((buffer)=>{this.rafEdits(buffer)})}else if(typeof data==="string"){if(data===required_server_key){authenticated=!0;return}}}}markEditsFinished(){this.edits.send(new ArrayBuffer(0))}kickAllStylesheetsOnPage(){let stylesheets=document.querySelectorAll("link[rel=stylesheet]");for(let i=0;i{if(contents[key])contents[key].push(value);else contents[key]=[value]}),{valid:form.checkValidity(),values:contents}}function retrieveSelectValue(target){let options=target.selectedOptions,values=[];for(let i=0;icontents={...contents,...obj};if(event instanceof WheelEvent)extend(serializeWheelEvent(event));if(event instanceof MouseEvent)extend(serializeMouseEvent(event));if(event instanceof KeyboardEvent)extend(serializeKeyboardEvent(event));if(event instanceof InputEvent)extend(serializeInputEvent(event,target));if(event instanceof PointerEvent)extend(serializePointerEvent(event));if(event instanceof AnimationEvent)extend(serializeAnimationEvent(event));if(event instanceof TransitionEvent)extend({property_name:event.propertyName,elapsed_time:event.elapsedTime,pseudo_element:event.pseudoElement});if(event instanceof CompositionEvent)extend({data:event.data});if(event instanceof DragEvent)extend(serializeDragEvent(event));if(event instanceof FocusEvent)extend({});if(event instanceof ClipboardEvent)extend({});if(event instanceof CustomEvent){let detail=event.detail;if(detail instanceof ResizeObserverEntry)extend(serializeResizeEventDetail(detail));else if(detail instanceof IntersectionObserverEntry)extend(serializeIntersectionEventDetail(detail))}if(typeof TouchEvent!=="undefined"&&event instanceof TouchEvent)extend(serializeTouchEvent(event));if(event.type==="submit"||event.type==="reset"||event.type==="click"||event.type==="change"||event.type==="input")extend(serializeInputEvent(event,target));if(event instanceof DragEvent);if(event.type==="scroll")extend(serializeScrollEvent(event));return contents}function toSerializableResizeObserverSize(size,is_inline_width){return[is_inline_width?size.inlineSize:size.blockSize,is_inline_width?size.blockSize:size.inlineSize]}function serializeResizeEventDetail(detail){let is_inline_width=!0;if(detail.target instanceof HTMLElement){if(window.getComputedStyle(detail.target).getPropertyValue("writing-mode")!=="horizontal-tb")is_inline_width=!1}return{border_box_size:detail.borderBoxSize!==void 0?toSerializableResizeObserverSize(detail.borderBoxSize[0],is_inline_width):detail.contentRect,content_box_size:detail.contentBoxSize!==void 0?toSerializableResizeObserverSize(detail.contentBoxSize[0],is_inline_width):detail.contentRect,content_rect:detail.contentRect}}function serializeIntersectionEventDetail(detail){return{bounding_client_rect:detail.boundingClientRect,intersection_ratio:detail.intersectionRatio,intersection_rect:detail.intersectionRect,is_intersecting:detail.isIntersecting,root_bounds:detail.rootBounds,time_ms:Math.floor(Date.now()+detail.time)}}function serializeInputEvent(event,target){let contents={};if(target instanceof HTMLElement){let values=retrieveValues(event,target);contents.values=values.values,contents.valid=values.valid}if(event.target instanceof HTMLInputElement){let target2=event.target,value=target2.value??target2.textContent??"";if(target2.type==="checkbox")value=target2.checked?"true":"false";else if(target2.type==="radio")value=target2.value;contents.value=value}if(event.target instanceof HTMLTextAreaElement)contents.value=event.target.value;if(event.target instanceof HTMLSelectElement)contents.value=retrieveSelectValue(event.target).join(",");if(contents.value===void 0)contents.value="";return contents}function serializeWheelEvent(event){return{delta_x:event.deltaX,delta_y:event.deltaY,delta_z:event.deltaZ,delta_mode:event.deltaMode}}function serializeTouchEvent(event){return{alt_key:event.altKey??!1,ctrl_key:event.ctrlKey??!1,meta_key:event.metaKey??!1,shift_key:event.shiftKey??!1,changed_touches:serializeTouchList(event.changedTouches),target_touches:serializeTouchList(event.targetTouches),touches:serializeTouchList(event.touches)}}function serializePointerEvent(event){return{alt_key:event.altKey??!1,button:event.button,buttons:event.buttons,client_x:event.clientX,client_y:event.clientY,ctrl_key:event.ctrlKey??!1,meta_key:event.metaKey??!1,page_x:event.pageX,page_y:event.pageY,screen_x:event.screenX,screen_y:event.screenY,shift_key:event.shiftKey??!1,pointer_id:event.pointerId,width:event.width,height:event.height,pressure:event.pressure,tangential_pressure:event.tangentialPressure,tilt_x:event.tiltX,tilt_y:event.tiltY,twist:event.twist,pointer_type:event.pointerType,is_primary:event.isPrimary}}function serializeTouchList(touchList){let serializedTouches=[];for(let i=0;i0)files={files:{placeholder:[]}};return{mouse:{alt_key:event.altKey??!1,ctrl_key:event.ctrlKey??!1,meta_key:event.metaKey??!1,shift_key:event.shiftKey??!1,...serializeMouseEvent(event)},files}}function serializeScrollEvent(event){let scrollLeft=0,scrollTop=0,scrollWidth=0,scrollHeight=0,clientWidth=0,clientHeight=0;if(event.target instanceof Element)scrollLeft=event.target.scrollLeft,scrollTop=event.target.scrollTop,scrollWidth=event.target.scrollWidth,scrollHeight=event.target.scrollHeight,clientWidth=event.target.clientWidth,clientHeight=event.target.clientHeight;else if(event.target===document)scrollLeft=window.scrollX||document.documentElement.scrollLeft,scrollTop=window.scrollY||document.documentElement.scrollTop,scrollWidth=document.documentElement.scrollWidth,scrollHeight=document.documentElement.scrollHeight,clientWidth=document.documentElement.clientWidth,clientHeight=document.documentElement.clientHeight;return{scroll_left:scrollLeft,scroll_top:scrollTop,scroll_width:scrollWidth,scroll_height:scrollHeight,client_width:clientWidth,client_height:clientHeight}}var JSChannel_;if(RawInterpreter!==void 0&&RawInterpreter!==null)JSChannel_=RawInterpreter;class NativeInterpreter extends JSChannel_{intercept_link_redirects;ipc;edits;eventsPath;headless;kickStylesheets;queuedBytes=[];liveview;constructor(eventsPath,headless){super();this.eventsPath=eventsPath,this.kickStylesheets=!1,this.headless=headless}initialize(root){this.intercept_link_redirects=!0,this.liveview=!1,window.addEventListener("dragover",function(e){if(e.target instanceof Element&&e.target.tagName!="INPUT")e.preventDefault()},!1),window.addEventListener("drop",function(e){if(!(e.target instanceof Element))return;e.preventDefault()},!1),window.addEventListener("click",(event)=>{let target=event.target;if(target instanceof HTMLInputElement&&target.getAttribute("type")==="file"){let target_id=getTargetId(target);if(target_id!==null){let message=this.serializeIpcMessage("file_dialog",{event:"change&input",accept:target.getAttribute("accept"),directory:target.getAttribute("webkitdirectory")==="true",multiple:target.hasAttribute("multiple"),target:target_id,bubbles:event.bubbles});this.ipc.postMessage(message),event.preventDefault()}}}),this.ipc=window.ipc;let handler=(event)=>this.handleEvent(event,event.type,!0);super.initialize(root,handler)}serializeIpcMessage(method,params={}){return JSON.stringify({method,params})}scrollTo(id,options){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollIntoView(options),!0;return!1}scroll(id,x,y,behavior){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scroll({top:y,left:x,behavior}),!0;return!1}getScrollHeight(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollHeight}getScrollLeft(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollLeft}getScrollTop(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollTop}getScrollWidth(id){let node=this.nodes[id];if(node instanceof HTMLElement)return node.scrollWidth}getClientRect(id){let node=this.nodes[id];if(node instanceof HTMLElement){let rect=node.getBoundingClientRect();return{type:"GetClientRect",origin:[rect.x,rect.y],size:[rect.width,rect.height]}}}setFocus(id,focus){let node=this.nodes[id];if(node instanceof HTMLElement)if(focus)node.focus();else node.blur()}handleWindowsDragDrop(){if(window.dxDragLastElement){let dragLeaveEvent=new DragEvent("dragleave",{bubbles:!0,cancelable:!0});window.dxDragLastElement.dispatchEvent(dragLeaveEvent);let data=new DataTransfer,file=new File(["content"],"file.txt",{type:"text/plain"});data.items.add(file);let dragDropEvent=new DragEvent("drop",{bubbles:!0,cancelable:!0,dataTransfer:data});window.dxDragLastElement.dispatchEvent(dragDropEvent),window.dxDragLastElement=null}}handleWindowsDragOver(xPos,yPos){let displayScaleFactor=window.devicePixelRatio||1;xPos/=displayScaleFactor,yPos/=displayScaleFactor;let element=document.elementFromPoint(xPos,yPos);if(element!=window.dxDragLastElement){if(window.dxDragLastElement){let dragLeaveEvent=new DragEvent("dragleave",{bubbles:!0,cancelable:!0});window.dxDragLastElement.dispatchEvent(dragLeaveEvent)}let dragOverEvent=new DragEvent("dragover",{bubbles:!0,cancelable:!0});element.dispatchEvent(dragOverEvent),window.dxDragLastElement=element}}handleWindowsDragLeave(){if(window.dxDragLastElement){let dragLeaveEvent=new DragEvent("dragleave",{bubbles:!0,cancelable:!0});window.dxDragLastElement.dispatchEvent(dragLeaveEvent),window.dxDragLastElement=null}}loadChild(array){let node=this.stack[this.stack.length-1];for(let i=0;i0;end--)node=node.nextSibling}return node}appendChildren(id,many){let root=this.nodes[id],els=this.stack.splice(this.stack.length-many);for(let k=0;k{this.flushQueuedBytes(),this.markEditsFinished()})}waitForRequest(editsPath,required_server_key){this.edits=new WebSocket(editsPath);let authenticated=!1;this.edits.onclose=()=>{setTimeout(()=>{if(this.edits.url!=editsPath)return;this.waitForRequest(editsPath,required_server_key)},100)},this.edits.onmessage=(event)=>{let data=event.data;if(data instanceof Blob){if(!authenticated)return;data.arrayBuffer().then((buffer)=>{this.rafEdits(buffer)})}else if(typeof data==="string"){if(data===required_server_key){authenticated=!0;return}}}}markEditsFinished(){this.edits.send(new ArrayBuffer(0))}kickAllStylesheetsOnPage(){let stylesheets=document.querySelectorAll("link[rel=stylesheet]");for(let i=0;i for Synthetic { - fn from(e: &Event) -> Self { - Synthetic::new(e.clone()) - } -} - -impl HasClipboardData for Synthetic { +impl HasClipboardData for Synthetic { fn as_any(&self) -> &dyn std::any::Any { &self.event } } impl WebEventExt for dioxus_html::ClipboardData { - type WebEvent = web_sys::Event; + type WebEvent = web_sys::ClipboardEvent; #[inline(always)] fn try_as_web_event(&self) -> Option { - self.downcast::().cloned() + self.downcast::().cloned() } } diff --git a/packages/web/src/events/drag.rs b/packages/web/src/events/drag.rs index 090f4a91ee..96daf1f13b 100644 --- a/packages/web/src/events/drag.rs +++ b/packages/web/src/events/drag.rs @@ -31,16 +31,30 @@ impl ModifiersInteraction for Synthetic { fn modifiers(&self) -> Modifiers { let mut modifiers = Modifiers::empty(); - if self.event.alt_key() { + // Handle undefined modifier key values from browser autofill + // Convert JsValue to bool, defaulting to false if undefined + if wasm_bindgen::JsValue::from(self.event.alt_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::ALT); } - if self.event.ctrl_key() { + if wasm_bindgen::JsValue::from(self.event.ctrl_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::CONTROL); } - if self.event.meta_key() { + if wasm_bindgen::JsValue::from(self.event.meta_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::META); } - if self.event.shift_key() { + if wasm_bindgen::JsValue::from(self.event.shift_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::SHIFT); } diff --git a/packages/web/src/events/keyboard.rs b/packages/web/src/events/keyboard.rs index fe775d1ee1..5b967a5759 100644 --- a/packages/web/src/events/keyboard.rs +++ b/packages/web/src/events/keyboard.rs @@ -10,11 +10,19 @@ use super::{Synthetic, WebEventExt}; impl HasKeyboardData for Synthetic { fn key(&self) -> Key { - Key::from_str(self.event.key().as_str()).unwrap_or(Key::Unidentified) + // Handle undefined key values from browser autofill + let key_str = wasm_bindgen::JsValue::from(self.event.key()) + .as_string() + .unwrap_or_else(|| "Unidentified".to_string()); + Key::from_str(&key_str).unwrap_or(Key::Unidentified) } fn code(&self) -> Code { - Code::from_str(self.event.code().as_str()).unwrap_or(Code::Unidentified) + // Handle undefined code values from browser autofill + let code_str = wasm_bindgen::JsValue::from(self.event.code()) + .as_string() + .unwrap_or_else(|| "Unidentified".to_string()); + Code::from_str(&code_str).unwrap_or(Code::Unidentified) } fn location(&self) -> Location { @@ -38,16 +46,30 @@ impl ModifiersInteraction for Synthetic { fn modifiers(&self) -> Modifiers { let mut modifiers = Modifiers::empty(); - if self.event.alt_key() { + // Handle undefined modifier key values from browser autofill + // Convert JsValue to bool, defaulting to false if undefined + if wasm_bindgen::JsValue::from(self.event.alt_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::ALT); } - if self.event.ctrl_key() { + if wasm_bindgen::JsValue::from(self.event.ctrl_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::CONTROL); } - if self.event.meta_key() { + if wasm_bindgen::JsValue::from(self.event.meta_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::META); } - if self.event.shift_key() { + if wasm_bindgen::JsValue::from(self.event.shift_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::SHIFT); } diff --git a/packages/web/src/events/mod.rs b/packages/web/src/events/mod.rs index 7bdfaebf54..100139428c 100644 --- a/packages/web/src/events/mod.rs +++ b/packages/web/src/events/mod.rs @@ -1,6 +1,4 @@ -use dioxus_html::{ - DragData, FormData, HtmlEventConverter, ImageData, MountedData, PlatformEventData, -}; +use dioxus_html::{FormData, HtmlEventConverter, ImageData, MountedData, PlatformEventData}; use form::WebFormData; use load::WebImageEvent; use wasm_bindgen::JsCast; @@ -51,43 +49,80 @@ fn downcast_event(event: &dioxus_html::PlatformEventData) -> &GenericWebSysEvent .expect("event should be a GenericWebSysEvent") } -impl HtmlEventConverter for WebEventConverter { - #[inline(always)] - fn convert_animation_data( - &self, - event: &dioxus_html::PlatformEventData, - ) -> dioxus_html::AnimationData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - - #[inline(always)] - fn convert_clipboard_data( - &self, - event: &dioxus_html::PlatformEventData, - ) -> dioxus_html::ClipboardData { - Synthetic::new(downcast_event(event).raw.clone()).into() - } - - #[inline(always)] - fn convert_composition_data( - &self, - event: &dioxus_html::PlatformEventData, - ) -> dioxus_html::CompositionData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - - #[inline(always)] - fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData { - let event = downcast_event(event); - DragData::new(Synthetic::new( - event.raw.clone().unchecked_into::(), - )) - } +macro_rules! impl_safe_converter { + ( + $( + ($fn_name:ident, $dioxus_event:ty, $web_sys_event:ty), + )* + ) => { + $( + #[inline(always)] + fn $fn_name(&self, event: &dioxus_html::PlatformEventData) -> $dioxus_event { + let raw_event = &downcast_event(event).raw; + if let Ok(event) = raw_event.clone().dyn_into::<$web_sys_event>() { + <$dioxus_event>::new(Synthetic::new(event)) + } else { + <$dioxus_event>::default() + } + } + )* + }; +} - #[inline(always)] - fn convert_focus_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FocusData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } +impl HtmlEventConverter for WebEventConverter { + impl_safe_converter!( + ( + convert_animation_data, + dioxus_html::AnimationData, + web_sys::AnimationEvent + ), + ( + convert_clipboard_data, + dioxus_html::ClipboardData, + web_sys::ClipboardEvent + ), + ( + convert_composition_data, + dioxus_html::CompositionData, + web_sys::CompositionEvent + ), + (convert_drag_data, dioxus_html::DragData, web_sys::DragEvent), + ( + convert_focus_data, + dioxus_html::FocusData, + web_sys::FocusEvent + ), + ( + convert_keyboard_data, + dioxus_html::KeyboardData, + web_sys::KeyboardEvent + ), + ( + convert_mouse_data, + dioxus_html::MouseData, + web_sys::MouseEvent + ), + ( + convert_pointer_data, + dioxus_html::PointerData, + web_sys::PointerEvent + ), + ( + convert_touch_data, + dioxus_html::TouchData, + web_sys::TouchEvent + ), + ( + convert_transition_data, + dioxus_html::TransitionData, + web_sys::TransitionEvent + ), + ( + convert_wheel_data, + dioxus_html::WheelData, + web_sys::WheelEvent + ), + ); #[inline(always)] fn convert_form_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FormData { @@ -102,14 +137,6 @@ impl HtmlEventConverter for WebEventConverter { ImageData::new(WebImageEvent::new(event.raw.clone(), error)) } - #[inline(always)] - fn convert_keyboard_data( - &self, - event: &dioxus_html::PlatformEventData, - ) -> dioxus_html::KeyboardData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - #[inline(always)] fn convert_media_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MediaData { Synthetic::new(downcast_event(event).raw.clone()).into() @@ -134,19 +161,6 @@ impl HtmlEventConverter for WebEventConverter { } } - #[inline(always)] - fn convert_mouse_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MouseData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - - #[inline(always)] - fn convert_pointer_data( - &self, - event: &dioxus_html::PlatformEventData, - ) -> dioxus_html::PointerData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - #[inline(always)] fn convert_resize_data( &self, @@ -179,19 +193,6 @@ impl HtmlEventConverter for WebEventConverter { Synthetic::new(downcast_event(event).raw.clone()).into() } - #[inline(always)] - fn convert_touch_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::TouchData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - - #[inline(always)] - fn convert_transition_data( - &self, - event: &dioxus_html::PlatformEventData, - ) -> dioxus_html::TransitionData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } - #[inline(always)] fn convert_visible_data( &self, @@ -200,11 +201,6 @@ impl HtmlEventConverter for WebEventConverter { Synthetic::::from(downcast_event(event).raw.clone()) .into() } - - #[inline(always)] - fn convert_wheel_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::WheelData { - Synthetic::::from(downcast_event(event).raw.clone()).into() - } } /// A extension trait for web-sys events that provides a way to get the event as a web-sys event. @@ -254,37 +250,5 @@ pub(crate) fn load_document() -> Document { .expect("should have access to the Document") } -macro_rules! uncheck_convert { - ($t:ty) => { - impl From for Synthetic<$t> { - #[inline] - fn from(e: Event) -> Self { - let e: $t = e.unchecked_into(); - Self::new(e) - } - } - - impl From<&Event> for Synthetic<$t> { - #[inline] - fn from(e: &Event) -> Self { - let e: &$t = e.unchecked_ref(); - Self::new(e.clone()) - } - } - }; - ($($t:ty),+ $(,)?) => { - $(uncheck_convert!($t);)+ - }; -} - -uncheck_convert![ - web_sys::CompositionEvent, - web_sys::KeyboardEvent, - web_sys::TouchEvent, - web_sys::PointerEvent, - web_sys::WheelEvent, - web_sys::AnimationEvent, - web_sys::TransitionEvent, - web_sys::MouseEvent, - web_sys::FocusEvent, -]; +// ResizeObserverEntry and IntersectionObserverEntry need custom From implementations +// because they come from CustomEvent details and are handled in their respective modules diff --git a/packages/web/src/events/mouse.rs b/packages/web/src/events/mouse.rs index 4f54f34c6a..fd56f075d0 100644 --- a/packages/web/src/events/mouse.rs +++ b/packages/web/src/events/mouse.rs @@ -32,16 +32,30 @@ impl ModifiersInteraction for Synthetic { fn modifiers(&self) -> Modifiers { let mut modifiers = Modifiers::empty(); - if self.event.alt_key() { + // Handle undefined modifier key values from browser autofill + // Convert JsValue to bool, defaulting to false if undefined + if wasm_bindgen::JsValue::from(self.event.alt_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::ALT); } - if self.event.ctrl_key() { + if wasm_bindgen::JsValue::from(self.event.ctrl_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::CONTROL); } - if self.event.meta_key() { + if wasm_bindgen::JsValue::from(self.event.meta_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::META); } - if self.event.shift_key() { + if wasm_bindgen::JsValue::from(self.event.shift_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::SHIFT); } diff --git a/packages/web/src/events/pointer.rs b/packages/web/src/events/pointer.rs index 2764122eb3..c50acebb16 100644 --- a/packages/web/src/events/pointer.rs +++ b/packages/web/src/events/pointer.rs @@ -78,16 +78,30 @@ impl ModifiersInteraction for Synthetic { fn modifiers(&self) -> Modifiers { let mut modifiers = Modifiers::empty(); - if self.event.alt_key() { + // Handle undefined modifier key values from browser autofill + // Convert JsValue to bool, defaulting to false if undefined + if wasm_bindgen::JsValue::from(self.event.alt_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::ALT); } - if self.event.ctrl_key() { + if wasm_bindgen::JsValue::from(self.event.ctrl_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::CONTROL); } - if self.event.meta_key() { + if wasm_bindgen::JsValue::from(self.event.meta_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::META); } - if self.event.shift_key() { + if wasm_bindgen::JsValue::from(self.event.shift_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::SHIFT); } diff --git a/packages/web/src/events/touch.rs b/packages/web/src/events/touch.rs index 839070494d..a69d5564fd 100644 --- a/packages/web/src/events/touch.rs +++ b/packages/web/src/events/touch.rs @@ -10,16 +10,30 @@ impl ModifiersInteraction for Synthetic { fn modifiers(&self) -> Modifiers { let mut modifiers = Modifiers::empty(); - if self.event.alt_key() { + // Handle undefined modifier key values from browser autofill + // Convert JsValue to bool, defaulting to false if undefined + if wasm_bindgen::JsValue::from(self.event.alt_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::ALT); } - if self.event.ctrl_key() { + if wasm_bindgen::JsValue::from(self.event.ctrl_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::CONTROL); } - if self.event.meta_key() { + if wasm_bindgen::JsValue::from(self.event.meta_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::META); } - if self.event.shift_key() { + if wasm_bindgen::JsValue::from(self.event.shift_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::SHIFT); } diff --git a/packages/web/src/events/wheel.rs b/packages/web/src/events/wheel.rs index 3fe8136efd..e4b84851e8 100644 --- a/packages/web/src/events/wheel.rs +++ b/packages/web/src/events/wheel.rs @@ -53,16 +53,30 @@ impl ModifiersInteraction for Synthetic { fn modifiers(&self) -> Modifiers { let mut modifiers = Modifiers::empty(); - if self.event.alt_key() { + // Handle undefined modifier key values from browser autofill + // Convert JsValue to bool, defaulting to false if undefined + if wasm_bindgen::JsValue::from(self.event.alt_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::ALT); } - if self.event.ctrl_key() { + if wasm_bindgen::JsValue::from(self.event.ctrl_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::CONTROL); } - if self.event.meta_key() { + if wasm_bindgen::JsValue::from(self.event.meta_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::META); } - if self.event.shift_key() { + if wasm_bindgen::JsValue::from(self.event.shift_key()) + .as_bool() + .unwrap_or(false) + { modifiers.insert(Modifiers::SHIFT); }