dioxus_web/events/
selection.rs1use 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}