1mod list_item;
2pub use list_item::*;
3
4mod check_list_item;
5pub use check_list_item::*;
6
7mod radio_list_item;
8pub use radio_list_item::*;
9
10mod separator;
11pub use separator::*;
12
13mod list_index;
14pub use list_index::ListIndex;
15
16mod selected_detail;
17pub use selected_detail::{IndexDiff, SelectedDetail};
18
19mod action_detail;
20pub use action_detail::ActionDetail;
21
22mod request_selected;
23pub use request_selected::{RequestSelectedDetail, RequestSelectedSource};
24
25mod graphic_type;
26pub use graphic_type::GraphicType;
27
28use dioxus::prelude::*;
29use gloo::events::EventListener;
30use wasm_bindgen::prelude::*;
31use web_sys::Node;
32
33use crate::{event_into_details, StaticCallback};
34
35#[wasm_bindgen(module = "/build/mwc-list.js")]
36extern "C" {
37 #[derive(Debug)]
38 #[wasm_bindgen(extends = Node)]
39 type List;
40
41 #[wasm_bindgen(getter, static_method_of = List)]
42 fn _dummy_loader() -> JsValue;
43
44 #[wasm_bindgen(method, getter)]
45 fn index(this: &List) -> JsValue;
46
47 #[wasm_bindgen(method)]
48 fn toggle(this: &List, index: usize, force: bool);
49
50 #[wasm_bindgen(method, js_name = getFocusedItemIndex)]
51 fn get_focused_item_index(this: &List) -> usize;
52
53 #[wasm_bindgen(method, js_name = focusItemAtIndex)]
54 fn focus_item_at_index(this: &List, index: usize);
55}
56
57loader_hack!(List);
58
59#[derive(Props)]
66pub struct ListProps<'a> {
67 #[props(default)]
68 pub activatable: bool,
69 #[props(default)]
70 pub root_tabbable: bool,
71 #[props(default)]
72 pub multi: bool,
73 #[props(default)]
74 pub wrap_focus: bool,
75 #[props(into)]
76 pub item_roles: Option<String>,
77 #[props(into)]
78 pub inner_role: Option<String>,
79 #[props(default)]
80 pub noninteractive: bool,
81 #[props(into)]
83 pub _onaction: Option<StaticCallback<ListIndex>>,
86 #[props(into)]
88 pub _onselected: Option<StaticCallback<SelectedDetail>>,
89 pub children: Element<'a>,
99
100 #[props(into, default)]
101 pub style: String,
102 #[props(into, default)]
103 pub class: String,
104 #[props(into)]
105 pub slot: Option<String>,
106}
107
108fn render<'a>(cx: Scope<'a, ListProps<'a>>) -> Element<'a> {
109 let id = crate::use_id(cx, "list");
110 let selected_listener = cx.use_hook(|| None);
111 let action_listener = cx.use_hook(|| None);
112 if let Some(elem) = crate::get_elem_by_id(id) {
113 let target = elem.clone();
114 let list = JsValue::from(elem).dyn_into::<List>().unwrap();
115 if let Some(listener) = cx.props._onselected.clone() {
116 *selected_listener = Some(EventListener::new(&target, "selected", move |event| {
117 let val = SelectedDetail::from(event_into_details(event));
118 listener.call(val)
119 }));
120 }
121 if let Some(listener) = cx.props._onaction.clone() {
122 *action_listener = Some(EventListener::new(&target, "action", move |_| {
123 let val: JsValue = list.index();
124 let index = ListIndex::from(val);
125 listener.call(index)
126 }));
127 }
128 }
129
130 render! {
131 mwc-list {
132 id: id,
133
134 activatable: bool_attr!(cx.props.activatable),
135 rootTabbable: bool_attr!(cx.props.root_tabbable),
136 multi: bool_attr!(cx.props.multi),
137 wrapFocus: bool_attr!(cx.props.wrap_focus),
138 itemRoles: optional_string_attr!(cx.props.item_roles),
139 innerRole: optional_string_attr!(cx.props.inner_role),
140 noninteractive: bool_attr!(cx.props.noninteractive),
141
142 style: string_attr!(cx.props.style),
143 class: string_attr!(cx.props.class),
144 slot: optional_string_attr!(cx.props.slot),
145
146 &cx.props.children
147 }
148 }
149}
150
151component!('a, MatList, ListProps, render, List, "list");