perspective_viewer/components/column_selector/
empty_column.rs1use std::collections::HashSet;
14
15use perspective_client::config::Expression;
16use web_sys::*;
17use yew::prelude::*;
18
19use crate::components::style::LocalStyle;
20use crate::css;
21use crate::custom_elements::ColumnDropDownElement;
22
23#[derive(Properties)]
24pub struct EmptyColumnProps {
25 pub column_dropdown: ColumnDropDownElement,
27
28 pub exclude: HashSet<String>,
30
31 pub on_select: Callback<InPlaceColumn>,
33}
34
35impl PartialEq for EmptyColumnProps {
36 fn eq(&self, _other: &Self) -> bool {
37 false
38 }
39}
40
41#[derive(Clone, Debug)]
42pub enum InPlaceColumn {
43 Column(String),
44 Expression(Expression<'static>),
45}
46
47pub enum EmptyColumnMsg {
48 KeyDown(u32),
49 Blur,
50 Input,
51}
52
53use EmptyColumnMsg::*;
54
55#[derive(Default)]
56pub struct EmptyColumn {
57 input_ref: NodeRef,
58}
59
60impl Component for EmptyColumn {
61 type Message = EmptyColumnMsg;
62 type Properties = EmptyColumnProps;
63
64 fn view(&self, ctx: &Context<Self>) -> Html {
65 let onblur = ctx.link().callback(|_| Blur);
66 let oninput = ctx.link().callback(|_| Input);
67 let onkeydown = ctx
68 .link()
69 .callback(|event: KeyboardEvent| KeyDown(event.key_code()));
70
71 html! {
72 <div class="pivot-column column-empty">
73 <LocalStyle href={css!("empty-column")} />
74 <input
75 spellcheck="false"
76 ref={self.input_ref.clone()}
77 {onblur}
78 {onkeydown}
79 {oninput}
80 class="column-empty-input"
81 />
82 </div>
83 }
84 }
85
86 fn changed(&mut self, _ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
87 if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
88 elem.blur().unwrap();
89 }
90
91 false
92 }
93
94 fn destroy(&mut self, ctx: &Context<Self>) {
95 ctx.props().column_dropdown.hide().unwrap();
96 }
97
98 fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
99 match msg {
100 Blur => {
101 ctx.props().column_dropdown.hide().unwrap();
102 if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
103 elem.set_value("");
104 }
105
106 false
107 },
108 KeyDown(40) => {
109 ctx.props().column_dropdown.item_down();
110 false
111 },
112 KeyDown(38) => {
113 ctx.props().column_dropdown.item_up();
114 false
115 },
116 KeyDown(13) => {
117 ctx.props().column_dropdown.item_select();
118 ctx.props().column_dropdown.hide().unwrap();
119 false
120 },
121 KeyDown(_) => false,
122 Input => {
123 if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
124 ctx.props().column_dropdown.autocomplete(
125 elem,
126 ctx.props().exclude.clone(),
127 ctx.props().on_select.clone(),
128 );
129 }
130
131 false
132 },
133 }
134 }
135
136 fn create(_ctx: &Context<Self>) -> Self {
137 Self::default()
138 }
139}