Skip to main content

perspective_viewer/components/
string_column_style.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use yew::prelude::*;
14
15use super::modal::{ModalLink, SetModalLink};
16use super::style::LocalStyle;
17use crate::components::form::select_enum_field::SelectEnumField;
18use crate::config::*;
19use crate::css;
20use crate::utils::WeakScope;
21
22/// Format-only widget for [`String`] columns. Renders the `format` enum
23/// only; color/color-mode UI is provided externally as primitive `Enum`
24/// + `Color` schema fields.
25#[derive(Properties)]
26pub struct StringColumnStyleProps {
27    pub config: Option<StringColumnStyleConfig>,
28
29    #[prop_or_default]
30    pub on_change: Callback<ColumnConfigFieldUpdate>,
31
32    #[prop_or_default]
33    pub keys: Vec<String>,
34
35    #[prop_or_default]
36    weak_link: WeakScope<StringColumnStyle>,
37}
38
39impl ModalLink<StringColumnStyle> for StringColumnStyleProps {
40    fn weak_link(&self) -> &'_ WeakScope<StringColumnStyle> {
41        &self.weak_link
42    }
43}
44
45impl PartialEq for StringColumnStyleProps {
46    fn eq(&self, other: &Self) -> bool {
47        self.config == other.config
48    }
49}
50
51pub enum StringColumnStyleMsg {
52    FormatChanged(Option<FormatMode>),
53}
54
55pub struct StringColumnStyle {
56    config: StringColumnStyleConfig,
57}
58
59impl Component for StringColumnStyle {
60    type Message = StringColumnStyleMsg;
61    type Properties = StringColumnStyleProps;
62
63    fn create(ctx: &Context<Self>) -> Self {
64        ctx.set_modal_link();
65        Self {
66            config: ctx.props().config.clone().unwrap_or_default(),
67        }
68    }
69
70    fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
71        let mut new_config = ctx.props().config.clone().unwrap_or_default();
72        if self.config != new_config {
73            std::mem::swap(&mut self.config, &mut new_config);
74            true
75        } else {
76            false
77        }
78    }
79
80    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
81        match msg {
82            StringColumnStyleMsg::FormatChanged(val) => {
83                self.config.format = val.unwrap_or_default();
84                self.dispatch_config(ctx);
85                true
86            },
87        }
88    }
89
90    fn view(&self, ctx: &Context<Self>) -> Html {
91        let format_mode_changed = ctx.link().callback(StringColumnStyleMsg::FormatChanged);
92        html! {
93            <>
94                <LocalStyle href={css!("column-style")} />
95                <div id="column-style-container" class="string-column-style-container">
96                    <SelectEnumField<FormatMode>
97                        label="format"
98                        on_change={format_mode_changed}
99                        current_value={self.config.format}
100                    />
101                </div>
102            </>
103        }
104    }
105}
106
107impl StringColumnStyle {
108    /// When this config has changed, we must signal the wrapper element.
109    fn dispatch_config(&self, ctx: &Context<Self>) {
110        let value = if self.config == StringColumnStyleConfig::default() {
111            serde_json::Map::new()
112        } else {
113            match serde_json::to_value(&self.config) {
114                Ok(serde_json::Value::Object(m)) => m,
115                _ => serde_json::Map::new(),
116            }
117        };
118
119        ctx.props().on_change.emit(ColumnConfigFieldUpdate {
120            keys: ctx.props().keys.clone(),
121            value,
122        });
123    }
124}