Skip to main content

dioxus_web/events/
selection.rs

1use super::{Synthetic, WebEventExt};
2use dioxus_html::{HasSelectionData, SelectionDirection, TextSelection};
3use wasm_bindgen::JsCast;
4use web_sys::{Event, HtmlInputElement, HtmlTextAreaElement};
5
6impl HasSelectionData for Synthetic<Event> {
7    fn selection(&self) -> Option<TextSelection> {
8        with_text_control(&self.event, |input| {
9            let start = input.selection_start().ok().flatten()? as usize;
10            let end = input.selection_end().ok().flatten()? as usize;
11            let direction = input
12                .selection_direction()
13                .ok()
14                .flatten()
15                .as_deref()
16                .map(selection_direction_from_web)
17                .unwrap_or_default();
18
19            Some(TextSelection::new(start..end, direction))
20        })
21        .flatten()
22    }
23
24    fn as_any(&self) -> &dyn std::any::Any {
25        &self.event
26    }
27}
28
29fn selection_direction_from_web(direction: &str) -> SelectionDirection {
30    match direction {
31        "forward" => SelectionDirection::Forward,
32        "backward" => SelectionDirection::Backward,
33        _ => SelectionDirection::None,
34    }
35}
36
37impl WebEventExt for dioxus_html::SelectionData {
38    type WebEvent = web_sys::Event;
39
40    #[inline(always)]
41    fn try_as_web_event(&self) -> Option<Self::WebEvent> {
42        self.downcast::<web_sys::Event>().cloned()
43    }
44}
45
46fn with_text_control<T>(event: &Event, f: impl FnOnce(TextControl<'_>) -> T) -> Option<T> {
47    event.target().and_then(|target| {
48        if let Some(input) = target.dyn_ref::<HtmlInputElement>() {
49            Some(f(TextControl::Input(input)))
50        } else {
51            target
52                .dyn_ref::<HtmlTextAreaElement>()
53                .map(|textarea| f(TextControl::TextArea(textarea)))
54        }
55    })
56}
57
58enum TextControl<'a> {
59    Input(&'a HtmlInputElement),
60    TextArea(&'a HtmlTextAreaElement),
61}
62
63impl TextControl<'_> {
64    fn selection_start(&self) -> Result<Option<u32>, wasm_bindgen::JsValue> {
65        match self {
66            Self::Input(input) => input.selection_start(),
67            Self::TextArea(textarea) => textarea.selection_start(),
68        }
69    }
70
71    fn selection_end(&self) -> Result<Option<u32>, wasm_bindgen::JsValue> {
72        match self {
73            Self::Input(input) => input.selection_end(),
74            Self::TextArea(textarea) => textarea.selection_end(),
75        }
76    }
77
78    fn selection_direction(&self) -> Result<Option<String>, wasm_bindgen::JsValue> {
79        match self {
80            Self::Input(input) => input.selection_direction(),
81            Self::TextArea(textarea) => textarea.selection_direction(),
82        }
83    }
84}