@perspective-dev/viewer 5.3.0 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/cdn/perspective-viewer.js +8 -8
  2. package/dist/cdn/perspective-viewer.js.map +3 -3
  3. package/dist/css/blueprint.css +1 -0
  4. package/dist/css/botanical.css +1 -1
  5. package/dist/css/dracula.css +1 -1
  6. package/dist/css/eggplant.css +1 -0
  7. package/dist/css/gruvbox-dark.css +1 -1
  8. package/dist/css/gruvbox.css +1 -1
  9. package/dist/css/icons.css +1 -1
  10. package/dist/css/intl/de.css +1 -1
  11. package/dist/css/intl/es.css +1 -1
  12. package/dist/css/intl/fr.css +1 -1
  13. package/dist/css/intl/ja.css +1 -1
  14. package/dist/css/intl/pt.css +1 -1
  15. package/dist/css/intl/zh.css +1 -1
  16. package/dist/css/intl.css +1 -1
  17. package/dist/css/ledger.css +1 -0
  18. package/dist/css/monokai.css +1 -1
  19. package/dist/css/nord.css +1 -0
  20. package/dist/css/phosphor.css +1 -1
  21. package/dist/css/pro-dark.css +1 -1
  22. package/dist/css/pro.css +1 -1
  23. package/dist/css/solarized-dark.css +1 -1
  24. package/dist/css/solarized.css +1 -1
  25. package/dist/css/themes.css +1 -1
  26. package/dist/css/vaporwave.css +1 -1
  27. package/dist/css/velvet.css +1 -0
  28. package/dist/docs/perspective-docs.json +1 -1
  29. package/dist/esm/column-format.d.ts +16 -3
  30. package/dist/esm/perspective-viewer.inline.js +9 -9
  31. package/dist/esm/perspective-viewer.inline.js.map +3 -3
  32. package/dist/esm/perspective-viewer.js +8 -8
  33. package/dist/esm/perspective-viewer.js.map +3 -3
  34. package/dist/wasm/perspective-viewer.d.ts +16 -16
  35. package/dist/wasm/perspective-viewer.js +107 -103
  36. package/dist/wasm/perspective-viewer.wasm +0 -0
  37. package/dist/wasm/perspective-viewer.wasm.d.ts +16 -16
  38. package/package.json +1 -1
  39. package/src/css/column-settings-panel.css +19 -0
  40. package/src/css/column-style.css +82 -0
  41. package/src/css/containers/tabs.css +13 -3
  42. package/src/css/dom/select.css +19 -8
  43. package/src/css/plugin-selector.css +1 -0
  44. package/src/css/plugin-settings-panel.css +72 -0
  45. package/src/css/viewer.css +0 -5
  46. package/src/rust/agent/tools.rs +5 -2
  47. package/src/rust/components/column_settings_sidebar/style_tab.rs +296 -237
  48. package/src/rust/components/containers/control_group.rs +91 -0
  49. package/src/rust/components/containers/mod.rs +1 -0
  50. package/src/rust/components/containers/select.rs +8 -2
  51. package/src/rust/components/datetime_column_style/simple.rs +15 -4
  52. package/src/rust/components/datetime_column_style.rs +50 -10
  53. package/src/rust/components/plugin_tab.rs +125 -87
  54. package/src/rust/components/settings_panel.rs +1 -0
  55. package/src/rust/components/status_bar.rs +0 -1
  56. package/src/rust/components/style_controls/number_string_format/digits_section.rs +22 -10
  57. package/src/rust/components/style_controls/number_string_format/misc_section.rs +6 -2
  58. package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -0
  59. package/src/rust/components/style_controls/number_string_format/types.rs +24 -0
  60. package/src/rust/components/style_controls/number_string_format.rs +37 -14
  61. package/src/rust/config/column_config_schema.rs +358 -27
  62. package/src/rust/config/datetime_column_style.rs +4 -21
  63. package/src/rust/config/number_string_format.rs +211 -18
  64. package/src/rust/presentation.rs +17 -0
  65. package/src/rust/queries/plugin_column_styles.rs +2 -2
  66. package/src/rust/renderer/dispatch.rs +34 -8
  67. package/src/rust/renderer/plugin_config.rs +55 -8
  68. package/src/themes/blueprint.css +190 -0
  69. package/src/themes/botanical.css +4 -17
  70. package/src/themes/defaults.css +2 -120
  71. package/src/themes/dracula.css +2 -14
  72. package/src/themes/eggplant.css +189 -0
  73. package/src/themes/gruvbox-dark.css +3 -15
  74. package/src/themes/gruvbox.css +1 -1
  75. package/src/themes/icons.css +1 -2
  76. package/src/themes/intl/de.css +23 -1
  77. package/src/themes/intl/es.css +23 -1
  78. package/src/themes/intl/fr.css +23 -1
  79. package/src/themes/intl/ja.css +23 -1
  80. package/src/themes/intl/pt.css +23 -1
  81. package/src/themes/intl/zh.css +23 -1
  82. package/src/themes/intl.css +26 -4
  83. package/src/themes/ledger.css +195 -0
  84. package/src/themes/monokai.css +2 -14
  85. package/src/themes/nord.css +186 -0
  86. package/src/themes/phosphor.css +2 -14
  87. package/src/themes/pro-dark.css +2 -16
  88. package/src/themes/pro.css +118 -0
  89. package/src/themes/solarized-dark.css +2 -16
  90. package/src/themes/themes.css +10 -5
  91. package/src/themes/vaporwave.css +2 -14
  92. package/src/themes/velvet.css +192 -0
  93. package/src/ts/column-format.ts +52 -2
  94. package/src/svg/dropdown-selector-light.svg +0 -3
  95. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-87bd21b215d0631a}/inline0.js +0 -0
  96. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-87bd21b215d0631a}/inline1.js +0 -0
  97. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-87bd21b215d0631a}/inline2.js +0 -0
  98. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-87bd21b215d0631a}/inline3.js +0 -0
  99. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-87bd21b215d0631a}/inline4.js +0 -0
  100. /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-87bd21b215d0631a}/inline5.js +0 -0
@@ -22,6 +22,13 @@ pub struct DatetimeStyleSimpleProps {
22
22
  pub enable_time_config: bool,
23
23
  pub config: SimpleDatetimeStyleConfig,
24
24
 
25
+ /// The plugin-declared default preset for each style select.
26
+ #[prop_or(SimpleDatetimeFormat::Short)]
27
+ pub date_style_default: SimpleDatetimeFormat,
28
+
29
+ #[prop_or(SimpleDatetimeFormat::Medium)]
30
+ pub time_style_default: SimpleDatetimeFormat,
31
+
25
32
  #[prop_or_default]
26
33
  pub on_change: Callback<SimpleDatetimeStyleConfig>,
27
34
 
@@ -37,7 +44,10 @@ impl ModalLink<DatetimeStyleSimple> for DatetimeStyleSimpleProps {
37
44
 
38
45
  impl PartialEq for DatetimeStyleSimpleProps {
39
46
  fn eq(&self, other: &Self) -> bool {
40
- self.enable_time_config == other.enable_time_config && self.config == other.config
47
+ self.enable_time_config == other.enable_time_config
48
+ && self.config == other.config
49
+ && self.date_style_default == other.date_style_default
50
+ && self.time_style_default == other.time_style_default
41
51
  }
42
52
  }
43
53
 
@@ -69,12 +79,12 @@ impl Component for DatetimeStyleSimple {
69
79
  fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
70
80
  match msg {
71
81
  DatetimeStyleSimpleMsg::DateStyleChanged(format) => {
72
- self.config.date_style = format.unwrap_or_default();
82
+ self.config.date_style = format.unwrap_or(ctx.props().date_style_default);
73
83
  self.dispatch_config(ctx);
74
84
  true
75
85
  },
76
86
  DatetimeStyleSimpleMsg::TimeStyleChanged(format) => {
77
- self.config.time_style = format.unwrap_or_default();
87
+ self.config.time_style = format.unwrap_or(ctx.props().time_style_default);
78
88
  self.dispatch_config(ctx);
79
89
  true
80
90
  },
@@ -99,13 +109,14 @@ impl Component for DatetimeStyleSimple {
99
109
  label="date-style"
100
110
  on_change={ctx.link().callback(DatetimeStyleSimpleMsg::DateStyleChanged)}
101
111
  current_value={self.config.date_style}
112
+ default_value={ctx.props().date_style_default}
102
113
  />
103
114
  if ctx.props().enable_time_config {
104
115
  <SelectEnumField<SimpleDatetimeFormat>
105
116
  label="time-style"
106
117
  on_change={ctx.link().callback(DatetimeStyleSimpleMsg::TimeStyleChanged)}
107
118
  current_value={self.config.time_style}
108
- default_value={SimpleDatetimeFormat::Medium}
119
+ default_value={ctx.props().time_style_default}
109
120
  />
110
121
  }
111
122
  </>
@@ -38,6 +38,9 @@ pub struct DatetimeColumnStyleProps {
38
38
  pub enable_time_config: bool,
39
39
  pub config: Option<DatetimeColumnStyleConfig>,
40
40
 
41
+ /// The active plugin's declared default `date_format`.
42
+ pub default_format: Rc<DatetimeFormatType>,
43
+
41
44
  #[prop_or_default]
42
45
  pub on_change: Callback<ColumnConfigFieldUpdate>,
43
46
 
@@ -57,7 +60,9 @@ impl ModalLink<DatetimeColumnStyle> for DatetimeColumnStyleProps {
57
60
 
58
61
  impl PartialEq for DatetimeColumnStyleProps {
59
62
  fn eq(&self, other: &Self) -> bool {
60
- self.enable_time_config == other.enable_time_config && self.config == other.config
63
+ self.enable_time_config == other.enable_time_config
64
+ && self.config == other.config
65
+ && self.default_format == other.default_format
61
66
  }
62
67
  }
63
68
 
@@ -90,7 +95,9 @@ impl Component for DatetimeColumnStyle {
90
95
  std::mem::swap(&mut self.config, &mut new_config);
91
96
  rerender = true;
92
97
  }
93
- if old.enable_time_config != ctx.props().enable_time_config {
98
+ if old.enable_time_config != ctx.props().enable_time_config
99
+ || old.default_format != ctx.props().default_format
100
+ {
94
101
  rerender = true;
95
102
  }
96
103
  rerender
@@ -99,22 +106,24 @@ impl Component for DatetimeColumnStyle {
99
106
  fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
100
107
  match msg {
101
108
  DatetimeColumnStyleMsg::TimezoneChanged(val) => {
109
+ let mut format = self.effective_format(ctx);
102
110
  if Some(&*USER_TIMEZONE) != val.as_ref() {
103
- *self.config.date_format.time_zone_mut() = val;
111
+ *format.time_zone_mut() = val;
104
112
  } else {
105
- *self.config.date_format.time_zone_mut() = None;
113
+ *format.time_zone_mut() = None;
106
114
  }
107
115
 
116
+ self.set_format(ctx, format);
108
117
  self.dispatch_config(ctx);
109
118
  true
110
119
  },
111
120
  DatetimeColumnStyleMsg::SimpleDatetimeStyleConfigChanged(simple) => {
112
- self.config.date_format = DatetimeFormatType::Simple(simple);
121
+ self.set_format(ctx, DatetimeFormatType::Simple(simple));
113
122
  self.dispatch_config(ctx);
114
123
  true
115
124
  },
116
125
  DatetimeColumnStyleMsg::CustomDatetimeStyleConfigChanged(custom) => {
117
- self.config.date_format = DatetimeFormatType::Custom(custom);
126
+ self.set_format(ctx, DatetimeFormatType::Custom(custom));
118
127
  self.dispatch_config(ctx);
119
128
  true
120
129
  },
@@ -122,6 +131,24 @@ impl Component for DatetimeColumnStyle {
122
131
  }
123
132
 
124
133
  fn view(&self, ctx: &Context<Self>) -> Html {
134
+ let format = self.effective_format(ctx);
135
+ let (date_style_default, time_style_default) = match &*ctx.props().default_format {
136
+ DatetimeFormatType::Simple(simple) => (simple.date_style, simple.time_style),
137
+ DatetimeFormatType::Custom(_) => {
138
+ (SimpleDatetimeFormat::Short, SimpleDatetimeFormat::Medium)
139
+ },
140
+ };
141
+
142
+ let simple_reset = {
143
+ let default_format = ctx.props().default_format.clone();
144
+ ctx.link().callback(move |_| {
145
+ DatetimeColumnStyleMsg::SimpleDatetimeStyleConfigChanged(match &*default_format {
146
+ DatetimeFormatType::Simple(simple) => simple.clone(),
147
+ DatetimeFormatType::Custom(_) => SimpleDatetimeStyleConfig::default(),
148
+ })
149
+ })
150
+ };
151
+
125
152
  html! {
126
153
  <>
127
154
  <div id="column-style-container" class="datetime-column-style-container">
@@ -131,10 +158,10 @@ impl Component for DatetimeColumnStyle {
131
158
  values={ALL_TIMEZONES.with(|x| (*x).clone())}
132
159
  default_value={(*USER_TIMEZONE).clone()}
133
160
  on_change={ctx.link().callback(DatetimeColumnStyleMsg::TimezoneChanged)}
134
- current_value={self.config.date_format.time_zone().as_ref().unwrap_or(&*USER_TIMEZONE).clone()}
161
+ current_value={format.time_zone().as_ref().unwrap_or(&*USER_TIMEZONE).clone()}
135
162
  />
136
163
  }
137
- if let DatetimeFormatType::Simple(config) = &self.config.date_format {
164
+ if let DatetimeFormatType::Simple(config) = &format {
138
165
  if ctx.props().enable_time_config {
139
166
  <div class="row">
140
167
  <button
@@ -149,15 +176,17 @@ impl Component for DatetimeColumnStyle {
149
176
  enable_time_config={ctx.props().enable_time_config}
150
177
  on_change={ctx.link().callback(DatetimeColumnStyleMsg::SimpleDatetimeStyleConfigChanged)}
151
178
  config={config.clone()}
179
+ {date_style_default}
180
+ {time_style_default}
152
181
  />
153
- } else if let DatetimeFormatType::Custom(config) = &self.config.date_format {
182
+ } else if let DatetimeFormatType::Custom(config) = &format {
154
183
  if ctx.props().enable_time_config {
155
184
  <div class="row">
156
185
  <button
157
186
  id="datetime_format"
158
187
  data-title="Custom"
159
188
  data-title-hover="Switch to Simple"
160
- onclick={ctx.link().callback(|_| DatetimeColumnStyleMsg::SimpleDatetimeStyleConfigChanged(SimpleDatetimeStyleConfig::default()))}
189
+ onclick={simple_reset}
161
190
  />
162
191
  </div>
163
192
  }
@@ -201,6 +230,17 @@ static USER_TIMEZONE: LazyLock<String> = LazyLock::new(|| {
201
230
  });
202
231
 
203
232
  impl DatetimeColumnStyle {
233
+ fn effective_format(&self, ctx: &Context<Self>) -> DatetimeFormatType {
234
+ self.config
235
+ .date_format
236
+ .clone()
237
+ .unwrap_or_else(|| (*ctx.props().default_format).clone())
238
+ }
239
+
240
+ fn set_format(&mut self, ctx: &Context<Self>, format: DatetimeFormatType) {
241
+ self.config.date_format = (format != *ctx.props().default_format).then_some(format);
242
+ }
243
+
204
244
  /// When this config has changed, we must signal the wrapper element.
205
245
  fn dispatch_config(&self, ctx: &Context<Self>) {
206
246
  let value = if self.config == DatetimeColumnStyleConfig::default() {
@@ -22,7 +22,9 @@ use yew::prelude::*;
22
22
  use crate::components::column_settings_sidebar::style_tab::primitive_field::{
23
23
  BoolField, ColorField, EnumField, NumberFieldPrimitive,
24
24
  };
25
+ use crate::components::containers::control_group::ControlGroup;
25
26
  use crate::config::ControlSpec;
27
+ use crate::presentation::Presentation;
26
28
  use crate::queries::get_plugin_config_schema;
27
29
  use crate::renderer::Renderer;
28
30
  use crate::session::Session;
@@ -47,6 +49,7 @@ pub struct PluginTabProps {
47
49
  pub plugin_config: PtrEqRc<serde_json::Map<String, serde_json::Value>>,
48
50
 
49
51
  // State
52
+ pub presentation: Presentation,
50
53
  pub renderer: Renderer,
51
54
  pub session: Session,
52
55
  }
@@ -95,98 +98,133 @@ pub fn PluginTab(props: &PluginTabProps) -> Html {
95
98
  })
96
99
  };
97
100
 
98
- let raw_config = &*props.plugin_config;
99
- let components = schema
100
- .iter()
101
- .cloned()
102
- .filter_map(|spec| {
103
- let component = match spec {
104
- ControlSpec::Enum {
105
- key,
106
- variants,
107
- default,
108
- } => {
109
- let current = raw_config
110
- .get(&key)
111
- .and_then(|v| v.as_str().map(|s| s.to_string()));
112
- html! {
113
- <EnumField
114
- field_key={key}
115
- {variants}
116
- {default}
117
- {current}
118
- on_change={on_change.clone()}
119
- />
120
- }
121
- },
122
- ControlSpec::Bool { key, default } => {
123
- let current = raw_config.get(&key).and_then(|v| v.as_bool());
124
- html! {
125
- <BoolField
126
- field_key={key}
127
- {default}
128
- {current}
129
- on_change={on_change.clone()}
130
- />
131
- }
132
- },
133
- ControlSpec::Color { key, default } => {
134
- let current = raw_config
135
- .get(&key)
136
- .and_then(|v| v.as_str().map(|s| s.to_string()));
137
- html! {
138
- <ColorField
139
- field_key={key}
140
- {default}
141
- {current}
142
- on_change={on_change.clone()}
143
- />
144
- }
145
- },
146
- ControlSpec::Number {
147
- key,
148
- default,
149
- min,
150
- max,
151
- step,
152
- include,
153
- } => {
154
- let current = raw_config.get(&key).and_then(|v| v.as_f64());
155
- html! {
156
- <NumberFieldPrimitive
157
- field_key={key}
158
- {default}
159
- {current}
160
- {min}
161
- {max}
162
- {step}
163
- {include}
164
- on_change={on_change.clone()}
165
- />
166
- }
167
- },
168
- // Column-scoped variants don't apply to
169
- // plugin-level config; drop silently.
170
- ControlSpec::AggregateDepth
171
- | ControlSpec::NumberSeriesStyle { .. }
172
- | ControlSpec::DatetimeFormat
173
- | ControlSpec::StringFormat
174
- | ControlSpec::Symbols { .. }
175
- | ControlSpec::NumberFormat
176
- | ControlSpec::String { .. }
177
- | ControlSpec::Palette { .. }
178
- | ControlSpec::GradientStops { .. } => {
179
- return None;
180
- },
181
- };
182
-
183
- Some(html! { <fieldset class="style-control">{ component }</fieldset> })
101
+ let on_group_toggle = {
102
+ let presentation = props.presentation.clone();
103
+ yew::Callback::from(move |(key, open): (String, bool)| {
104
+ presentation.set_control_group_collapsed(&key, !open);
184
105
  })
185
- .collect_vec();
106
+ };
186
107
 
108
+ let raw_config = &*props.plugin_config;
109
+ let components = render_specs(
110
+ &schema,
111
+ raw_config,
112
+ &on_change,
113
+ &props.presentation,
114
+ &on_group_toggle,
115
+ );
187
116
  html! {
188
117
  <div id="plugin-tab" class="sidebar_column scrollable">
189
118
  <div id="plugin-config-container" class="tab-section">{ components }</div>
190
119
  </div>
191
120
  }
192
121
  }
122
+
123
+ fn render_specs(
124
+ specs: &[ControlSpec],
125
+ raw_config: &serde_json::Map<String, serde_json::Value>,
126
+ on_change: &Callback<crate::config::ColumnConfigFieldUpdate>,
127
+ presentation: &Presentation,
128
+ on_group_toggle: &Callback<(String, bool)>,
129
+ ) -> Vec<Html> {
130
+ specs
131
+ .iter()
132
+ .filter_map(|spec| match spec {
133
+ ControlSpec::Group { key, fields } => {
134
+ let children =
135
+ render_specs(fields, raw_config, on_change, presentation, on_group_toggle);
136
+
137
+ (!children.is_empty()).then(|| {
138
+ html! {
139
+ <ControlGroup
140
+ key={format!("group::{key}")}
141
+ group_key={key.clone()}
142
+ open={!presentation.is_control_group_collapsed(key)}
143
+ on_toggle={on_group_toggle.clone()}
144
+ >
145
+ { children }
146
+ </ControlGroup>
147
+ }
148
+ })
149
+ },
150
+ leaf => {
151
+ let key = leaf.serialized_keys().join("+");
152
+ let component = render_leaf(leaf, raw_config, on_change)?;
153
+ Some(html! { <fieldset class="style-control" {key}>{ component }</fieldset> })
154
+ },
155
+ })
156
+ .collect_vec()
157
+ }
158
+
159
+ fn render_leaf(
160
+ spec: &ControlSpec,
161
+ raw_config: &serde_json::Map<String, serde_json::Value>,
162
+ on_change: &Callback<crate::config::ColumnConfigFieldUpdate>,
163
+ ) -> Option<Html> {
164
+ match spec.clone() {
165
+ ControlSpec::Enum {
166
+ key,
167
+ variants,
168
+ default,
169
+ } => {
170
+ let current = raw_config
171
+ .get(&key)
172
+ .and_then(|v| v.as_str().map(|s| s.to_string()));
173
+ Some(html! {
174
+ <EnumField
175
+ field_key={key}
176
+ {variants}
177
+ {default}
178
+ {current}
179
+ on_change={on_change.clone()}
180
+ />
181
+ })
182
+ },
183
+ ControlSpec::Bool { key, default } => {
184
+ let current = raw_config.get(&key).and_then(|v| v.as_bool());
185
+ Some(html! {
186
+ <BoolField field_key={key} {default} {current} on_change={on_change.clone()} />
187
+ })
188
+ },
189
+ ControlSpec::Color { key, default } => {
190
+ let current = raw_config
191
+ .get(&key)
192
+ .and_then(|v| v.as_str().map(|s| s.to_string()));
193
+ Some(html! {
194
+ <ColorField field_key={key} {default} {current} on_change={on_change.clone()} />
195
+ })
196
+ },
197
+ ControlSpec::Number {
198
+ key,
199
+ default,
200
+ min,
201
+ max,
202
+ step,
203
+ include,
204
+ } => {
205
+ let current = raw_config.get(&key).and_then(|v| v.as_f64());
206
+ Some(html! {
207
+ <NumberFieldPrimitive
208
+ field_key={key}
209
+ {default}
210
+ {current}
211
+ {min}
212
+ {max}
213
+ {step}
214
+ {include}
215
+ on_change={on_change.clone()}
216
+ />
217
+ })
218
+ },
219
+ ControlSpec::Group { .. }
220
+ | ControlSpec::AggregateDepth
221
+ | ControlSpec::NumberSeriesStyle { .. }
222
+ | ControlSpec::DatetimeFormat { .. }
223
+ | ControlSpec::StringFormat
224
+ | ControlSpec::Symbols { .. }
225
+ | ControlSpec::NumberFormat { .. }
226
+ | ControlSpec::String { .. }
227
+ | ControlSpec::Palette { .. }
228
+ | ControlSpec::GradientStops { .. } => None,
229
+ }
230
+ }
@@ -370,6 +370,7 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
370
370
  <PluginTab
371
371
  view_config={props.view_config.clone()}
372
372
  plugin_config={props.plugin_config.clone()}
373
+ presentation={presentation.clone()}
373
374
  renderer={renderer.clone()}
374
375
  session={session.clone()}
375
376
  // initial_width={width}
@@ -429,7 +429,6 @@ fn ThemeSelector(props: &ThemeSelectorProps) -> Html {
429
429
  <span class="icon" />
430
430
  <Select<String>
431
431
  id="theme_selector"
432
- class="invert"
433
432
  {values}
434
433
  selected={selected.to_owned()}
435
434
  on_select={props.on_change.clone()}
@@ -37,7 +37,7 @@ impl CustomNumberFormat {
37
37
  min=1.
38
38
  max=21.
39
39
  step=1.
40
- default=1.
40
+ default={ctx.props().defaults.minimum_integer_digits}
41
41
  current_value={self.config.minimum_integer_digits}
42
42
  on_change={ctx.link().callback(CustomNumberFormatMsg::MinimumIntegerDigits)}
43
43
  />
@@ -84,14 +84,23 @@ impl CustomNumberFormat {
84
84
  }
85
85
 
86
86
  fn float_section(&self, ctx: &yew::prelude::Context<Self>) -> yew::prelude::Html {
87
+ let defaults = &ctx.props().defaults;
87
88
  let fractional_value = Some((
88
- self.config.minimum_fraction_digits.unwrap_or(2.),
89
- self.config.maximum_fraction_digits.unwrap_or(2.),
89
+ self.config
90
+ .minimum_fraction_digits
91
+ .unwrap_or(defaults.fraction.0),
92
+ self.config
93
+ .maximum_fraction_digits
94
+ .unwrap_or(defaults.fraction.1),
90
95
  ));
91
96
 
92
97
  let significant_value = Some((
93
- self.config.minimum_significant_digits.unwrap_or(1.),
94
- self.config.maximum_significant_digits.unwrap_or(21.),
98
+ self.config
99
+ .minimum_significant_digits
100
+ .unwrap_or(defaults.significant.0),
101
+ self.config
102
+ .maximum_significant_digits
103
+ .unwrap_or(defaults.significant.1),
95
104
  ));
96
105
 
97
106
  html! {
@@ -102,7 +111,7 @@ impl CustomNumberFormat {
102
111
  min=0.
103
112
  max=20.
104
113
  step=1.
105
- default={(2., 2.)}
114
+ default={defaults.fraction}
106
115
  current_value={fractional_value}
107
116
  on_change={ctx.link().callback(CustomNumberFormatMsg::FracChange)}
108
117
  />
@@ -113,7 +122,7 @@ impl CustomNumberFormat {
113
122
  min=1.
114
123
  max=21.
115
124
  step=1.
116
- default={(1., 21.)}
125
+ default={defaults.significant}
117
126
  current_value={significant_value}
118
127
  on_change={ctx.link().callback(CustomNumberFormatMsg::SigChange)}
119
128
  />
@@ -121,17 +130,20 @@ impl CustomNumberFormat {
121
130
  { self.rounding_increment(ctx) }
122
131
  <SelectEnumField<RoundingPriority>
123
132
  label="rounding-priority"
124
- current_value={self.config.rounding_priority}
133
+ current_value={self.config.rounding_priority.unwrap_or(defaults.rounding_priority)}
134
+ default_value={defaults.rounding_priority}
125
135
  on_change={ctx.link().callback(CustomNumberFormatMsg::RoundingPriority)}
126
136
  />
127
137
  <SelectEnumField<RoundingMode>
128
138
  label="rounding-mode"
129
- current_value={self.config.rounding_mode}
139
+ current_value={self.config.rounding_mode.unwrap_or(defaults.rounding_mode)}
140
+ default_value={defaults.rounding_mode}
130
141
  on_change={ctx.link().callback(CustomNumberFormatMsg::RoundingMode)}
131
142
  />
132
143
  <SelectEnumField<TrailingZeroDisplay>
133
144
  label="trailing-zero-display"
134
- current_value={self.config.trailing_zero_display}
145
+ current_value={self.config.trailing_zero_display.unwrap_or(defaults.trailing_zero_display)}
146
+ default_value={defaults.trailing_zero_display}
135
147
  on_change={ctx.link().callback(CustomNumberFormatMsg::TrailingZero)}
136
148
  />
137
149
  </>
@@ -32,23 +32,27 @@ impl CustomNumberFormat {
32
32
  None
33
33
  };
34
34
 
35
+ let defaults = &ctx.props().defaults;
35
36
  html! {
36
37
  <>
37
38
  <SelectEnumField<NotationName>
38
39
  label="notation"
39
40
  on_change={ctx.link().callback(CustomNumberFormatMsg::NotationChanged)}
40
41
  current_value={self.notation.unwrap_or_default()}
42
+ default_value={NotationName::from(&defaults.notation)}
41
43
  />
42
44
  { compact_display_checkbox }
43
45
  <SelectEnumField<UseGrouping>
44
46
  label="use-grouping"
45
47
  on_change={ctx.link().callback(CustomNumberFormatMsg::UseGrouping)}
46
- current_value={self.config.use_grouping.unwrap_or_default()}
48
+ current_value={self.config.use_grouping.unwrap_or(defaults.use_grouping)}
49
+ default_value={defaults.use_grouping}
47
50
  />
48
51
  <SelectEnumField<SignDisplay>
49
52
  label="sign-display"
50
53
  on_change={ctx.link().callback(CustomNumberFormatMsg::SignDisplay)}
51
- current_value={self.config.sign_display.unwrap_or_default()}
54
+ current_value={self.config.sign_display.unwrap_or(defaults.sign_display)}
55
+ default_value={defaults.sign_display}
52
56
  />
53
57
  </>
54
58
  }
@@ -60,6 +60,7 @@ impl CustomNumberFormat {
60
60
  <SelectEnumField<NumberStyle>
61
61
  label="style"
62
62
  current_value={self.style}
63
+ default_value={NumberStyle::from(&ctx.props().defaults.style)}
63
64
  on_change={ctx.link().callback(CustomNumberFormatMsg::StyleChanged)}
64
65
  />
65
66
  { section }
@@ -12,6 +12,8 @@
12
12
 
13
13
  use strum::{Display, EnumIter};
14
14
 
15
+ use crate::config::{Notation, NumberFormatStyle};
16
+
15
17
  #[derive(Clone, PartialEq, Debug, Copy, Default, EnumIter, Display)]
16
18
  pub enum NumberStyle {
17
19
  #[default]
@@ -21,6 +23,17 @@ pub enum NumberStyle {
21
23
  Unit,
22
24
  }
23
25
 
26
+ impl From<&NumberFormatStyle> for NumberStyle {
27
+ fn from(style: &NumberFormatStyle) -> Self {
28
+ match style {
29
+ NumberFormatStyle::Decimal => Self::Decimal,
30
+ NumberFormatStyle::Currency(_) => Self::Currency,
31
+ NumberFormatStyle::Percent => Self::Percent,
32
+ NumberFormatStyle::Unit(_) => Self::Unit,
33
+ }
34
+ }
35
+ }
36
+
24
37
  #[derive(Clone, PartialEq, Debug, Copy, Default, Display, EnumIter)]
25
38
  pub enum NotationName {
26
39
  #[default]
@@ -29,3 +42,14 @@ pub enum NotationName {
29
42
  Engineering,
30
43
  Compact,
31
44
  }
45
+
46
+ impl From<&Notation> for NotationName {
47
+ fn from(notation: &Notation) -> Self {
48
+ match notation {
49
+ Notation::Standard => Self::Standard,
50
+ Notation::Scientific => Self::Scientific,
51
+ Notation::Engineering => Self::Engineering,
52
+ Notation::Compact(_) => Self::Compact,
53
+ }
54
+ }
55
+ }