feat(html): add scroll method to MountedData (#3722)
* feat(html): add `scroll` method to MountedData * feat(desktop): implement `scroll` method for DesktopElement * feat(liveview): implement `scroll` method for LiveviewElement * feat(web): implement `scroll` method for web_sys::Element * docs(examples): add new example for `scroll` method * fix(web): remove unncecessary f64 cast (clippy) * fix(interpreter): return missing boolean from js * docs(example): unwrap result instead of discarding its error * docs(examples): create scroll restoring example on routing * fix clippy --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
60c1b0ead6
commit
85b373deff
11 files changed
+757
-607
No files matched your search
Generated
+516
-605
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,73 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use dioxus::html::geometry::PixelsVector2D;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Routable, Debug, PartialEq)]
|
||||||
|
enum Route {
|
||||||
|
#[route("/")]
|
||||||
|
Home {},
|
||||||
|
#[route("/blog/:id")]
|
||||||
|
Blog { id: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dioxus::launch(App);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn App() -> Element {
|
||||||
|
use_context_provider(|| Signal::new(Scroll::default()));
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
Router::<Route> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn Blog(id: i32) -> Element {
|
||||||
|
rsx! {
|
||||||
|
GoBackButton { "Go back" }
|
||||||
|
div { "Blog post {id}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Scroll = Option<PixelsVector2D>;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn Home() -> Element {
|
||||||
|
let mut element: Signal<Option<Rc<MountedData>>> = use_signal(|| None);
|
||||||
|
let mut scroll = use_context::<Signal<Scroll>>();
|
||||||
|
|
||||||
|
_ = use_resource(move || async move {
|
||||||
|
if let (Some(element), Some(scroll)) = (element.read().as_ref(), *scroll.peek()) {
|
||||||
|
element
|
||||||
|
.scroll(scroll, ScrollBehavior::Instant)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
height: "300px",
|
||||||
|
overflow_y: "auto",
|
||||||
|
border: "1px solid black",
|
||||||
|
|
||||||
|
onmounted: move |event| element.set(Some(event.data())),
|
||||||
|
|
||||||
|
onscroll: move |_| async move {
|
||||||
|
if let Some(element) = element.cloned() {
|
||||||
|
scroll.set(Some(element.get_scroll_offset().await.unwrap()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
for i in 0..100 {
|
||||||
|
div { height: "20px",
|
||||||
|
|
||||||
|
Link { to: Route::Blog { id: i }, "Blog {i}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
//! Scroll elements using their MountedData
|
||||||
|
//!
|
||||||
|
//! Dioxus exposes a few helpful APIs around elements (mimicking the DOM APIs) to allow you to interact with elements
|
||||||
|
//! across the renderers. This includes scrolling, reading dimensions, and more.
|
||||||
|
//!
|
||||||
|
//! In this example we demonstrate how to scroll to a given y offset of the scrollable parent using the `scroll` method on the `MountedData`
|
||||||
|
|
||||||
|
use dioxus::html::geometry::PixelsVector2D;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dioxus::launch(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app() -> Element {
|
||||||
|
rsx! {
|
||||||
|
ScrollToCoordinates {}
|
||||||
|
ScrollToCoordinates {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn ScrollToCoordinates() -> Element {
|
||||||
|
let mut element = use_signal(|| None);
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div { border: "1px solid black", position: "relative",
|
||||||
|
|
||||||
|
div {
|
||||||
|
height: "300px",
|
||||||
|
overflow_y: "auto",
|
||||||
|
|
||||||
|
onmounted: move |event| element.set(Some(event.data())),
|
||||||
|
|
||||||
|
for i in 0..100 {
|
||||||
|
div { height: "20px", "Item {i}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div { position: "absolute", top: 0, right: 0,
|
||||||
|
input {
|
||||||
|
r#type: "number",
|
||||||
|
min: "0",
|
||||||
|
max: "99",
|
||||||
|
oninput: move |event| async move {
|
||||||
|
if let Some(ul) = element.cloned() {
|
||||||
|
let data = event.data();
|
||||||
|
if let Ok(value) = data.parsed::<f64>() {
|
||||||
|
ul.scroll(PixelsVector2D::new(0.0, 20.0 * value), ScrollBehavior::Smooth)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -104,6 +104,36 @@ impl RenderedElementBacking for DesktopElement {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scroll(
|
||||||
|
&self,
|
||||||
|
coordinates: PixelsVector2D,
|
||||||
|
behavior: dioxus_html::ScrollBehavior,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = MountedResult<()>>>> {
|
||||||
|
let script = format!(
|
||||||
|
"return window.interpreter.scroll({}, {}, {}, {});",
|
||||||
|
self.id.0,
|
||||||
|
coordinates.x,
|
||||||
|
coordinates.y,
|
||||||
|
serde_json::to_string(&behavior).expect("Failed to serialize ScrollBehavior")
|
||||||
|
);
|
||||||
|
let webview = self
|
||||||
|
.webview
|
||||||
|
.upgrade()
|
||||||
|
.expect("Webview should be alive if the element is being queried");
|
||||||
|
let fut = self.query.new_query::<bool>(&script, webview).resolve();
|
||||||
|
Box::pin(async move {
|
||||||
|
match fut.await {
|
||||||
|
Ok(true) => Ok(()),
|
||||||
|
Ok(false) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||||
|
Box::new(DesktopQueryError::FailedToQuery),
|
||||||
|
)),
|
||||||
|
Err(err) => {
|
||||||
|
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn set_focus(
|
fn set_focus(
|
||||||
&self,
|
&self,
|
||||||
focus: bool,
|
focus: bool,
|
||||||
|
|||||||
@@ -39,6 +39,15 @@ pub trait RenderedElementBacking: std::any::Any {
|
|||||||
Box::pin(async { Err(MountedError::NotSupported) })
|
Box::pin(async { Err(MountedError::NotSupported) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scroll to the given element offsets
|
||||||
|
fn scroll(
|
||||||
|
&self,
|
||||||
|
_coordinates: PixelsVector2D,
|
||||||
|
_behavior: ScrollBehavior,
|
||||||
|
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||||
|
Box::pin(async { Err(MountedError::NotSupported) })
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the focus on the element
|
/// Set the focus on the element
|
||||||
fn set_focus(&self, _focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
fn set_focus(&self, _focus: bool) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||||
Box::pin(async { Err(MountedError::NotSupported) })
|
Box::pin(async { Err(MountedError::NotSupported) })
|
||||||
@@ -119,6 +128,16 @@ impl MountedData {
|
|||||||
self.inner.scroll_to(behavior)
|
self.inner.scroll_to(behavior)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scroll to the given element offsets
|
||||||
|
#[doc(alias = "scrollTo")]
|
||||||
|
pub fn scroll(
|
||||||
|
&self,
|
||||||
|
coordinates: PixelsVector2D,
|
||||||
|
behavior: ScrollBehavior,
|
||||||
|
) -> Pin<Box<dyn Future<Output = MountedResult<()>>>> {
|
||||||
|
self.inner.scroll(coordinates, behavior)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the focus on the element
|
/// Set the focus on the element
|
||||||
#[doc(alias = "focus")]
|
#[doc(alias = "focus")]
|
||||||
#[doc(alias = "blur")]
|
#[doc(alias = "blur")]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[6449103750905854967, 17669692872757955279, 13069001215487072322, 11420464406527728232, 3770103091118609057, 5444526391971481782, 7965007982501706197, 5052021921702764563, 10988859153374944111, 16153602427306015669]
|
[6449103750905854967, 17669692872757955279, 13069001215487072322, 11420464406527728232, 3770103091118609057, 5444526391971481782, 15257049569425934744, 5052021921702764563, 10988859153374944111, 16153602427306015669]
|
||||||
@@ -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;i<options.length;i++)values.push(options[i].value);return values}function serializeEvent(event,target){let contents={},extend=(obj)=>contents={...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:event.changedTouches,target_touches:event.targetTouches,touches: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 serializeMouseEvent(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,offset_x:event.offsetX,offset_y:event.ofLine truncated
|
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;i<options.length;i++)values.push(options[i].value);return values}function serializeEvent(event,target){let contents={},extend=(obj)=>contents={...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:event.changedTouches,target_touches:event.targetTouches,touches: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 serializeMouseEvent(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,offset_x:event.offsetX,offset_y:event.ofLine truncated
|
||||||
@@ -115,6 +115,15 @@ export class NativeInterpreter extends JSChannel_ {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scroll(id: NodeId, x: number, y: number, behavior: ScrollBehavior): boolean {
|
||||||
|
const node = this.nodes[id];
|
||||||
|
if (node instanceof HTMLElement) {
|
||||||
|
node.scroll({ top: y, left: x, behavior });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
getScrollHeight(id: NodeId): number | undefined {
|
getScrollHeight(id: NodeId): number | undefined {
|
||||||
const node = this.nodes[id];
|
const node = this.nodes[id];
|
||||||
if (node instanceof HTMLElement) {
|
if (node instanceof HTMLElement) {
|
||||||
|
|||||||
@@ -94,6 +94,33 @@ impl RenderedElementBacking for LiveviewElement {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scroll(
|
||||||
|
&self,
|
||||||
|
coordinates: PixelsVector2D,
|
||||||
|
behavior: dioxus_html::ScrollBehavior,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = MountedResult<()>>>> {
|
||||||
|
let script = format!(
|
||||||
|
"return window.interpreter.scroll({}, {}, {}, {});",
|
||||||
|
self.id.0,
|
||||||
|
coordinates.x,
|
||||||
|
coordinates.y,
|
||||||
|
serde_json::to_string(&behavior).expect("Failed to serialize ScrollBehavior")
|
||||||
|
);
|
||||||
|
|
||||||
|
let fut = self.query.new_query::<bool>(&script).resolve();
|
||||||
|
Box::pin(async move {
|
||||||
|
match fut.await {
|
||||||
|
Ok(true) => Ok(()),
|
||||||
|
Ok(false) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
|
||||||
|
Box::new(DesktopQueryError::FailedToQuery),
|
||||||
|
)),
|
||||||
|
Err(err) => {
|
||||||
|
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn set_focus(
|
fn set_focus(
|
||||||
&self,
|
&self,
|
||||||
focus: bool,
|
focus: bool,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ features = [
|
|||||||
"ResizeObserverEntry",
|
"ResizeObserverEntry",
|
||||||
"ResizeObserverSize",
|
"ResizeObserverSize",
|
||||||
"ScrollRestoration",
|
"ScrollRestoration",
|
||||||
|
"ScrollToOptions",
|
||||||
"Text",
|
"Text",
|
||||||
"Touch",
|
"Touch",
|
||||||
"TouchEvent",
|
"TouchEvent",
|
||||||
|
|||||||
@@ -83,6 +83,27 @@ impl dioxus_html::RenderedElementBacking for Synthetic<web_sys::Element> {
|
|||||||
Box::pin(async { Ok(()) })
|
Box::pin(async { Ok(()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scroll(
|
||||||
|
&self,
|
||||||
|
coordinates: dioxus_html::geometry::PixelsVector2D,
|
||||||
|
behavior: dioxus_html::ScrollBehavior,
|
||||||
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = dioxus_html::MountedResult<()>>>> {
|
||||||
|
let options = web_sys::ScrollToOptions::new();
|
||||||
|
options.set_top(coordinates.y);
|
||||||
|
options.set_left(coordinates.x);
|
||||||
|
match behavior {
|
||||||
|
dioxus_html::ScrollBehavior::Instant => {
|
||||||
|
options.set_behavior(web_sys::ScrollBehavior::Instant);
|
||||||
|
}
|
||||||
|
dioxus_html::ScrollBehavior::Smooth => {
|
||||||
|
options.set_behavior(web_sys::ScrollBehavior::Smooth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.event.scroll_with_scroll_to_options(&options);
|
||||||
|
|
||||||
|
Box::pin(async { Ok(()) })
|
||||||
|
}
|
||||||
|
|
||||||
fn set_focus(
|
fn set_focus(
|
||||||
&self,
|
&self,
|
||||||
focus: bool,
|
focus: bool,
|
||||||
|
|||||||
Reference in new issue
Block a user