@perspective-dev/viewer 4.4.1 → 4.5.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.
- package/dist/cdn/perspective-viewer.js +1 -2
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/gruvbox-dark.css +1 -1
- package/dist/css/gruvbox.css +1 -1
- package/dist/css/icons.css +1 -1
- package/dist/css/intl/de.css +1 -1
- package/dist/css/intl/es.css +1 -1
- package/dist/css/intl/fr.css +1 -1
- package/dist/css/intl/ja.css +1 -1
- package/dist/css/intl/pt.css +1 -1
- package/dist/css/intl/zh.css +1 -1
- package/dist/css/intl.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/phosphor.css +1 -1
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/css/solarized-dark.css +1 -1
- package/dist/css/solarized.css +1 -1
- package/dist/css/themes.css +1 -1
- package/dist/css/vaporwave.css +1 -1
- package/dist/esm/bootstrap.d.ts +2 -1
- package/dist/esm/column-format.d.ts +51 -0
- package/dist/esm/extensions.d.ts +2 -0
- package/dist/esm/perspective-viewer.d.ts +3 -1
- package/dist/esm/perspective-viewer.inline.js +1 -2
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +1 -2
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/perspective-viewer.worker.d.ts +2 -0
- package/dist/esm/plugin.d.ts +16 -72
- package/dist/esm/ts-rs/ColumnSelectMode.d.ts +1 -0
- package/dist/esm/ts-rs/PluginStaticConfig.d.ts +77 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -3
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +7 -4
- package/dist/wasm/perspective-viewer.d.ts +77 -18
- package/dist/wasm/perspective-viewer.js +302 -148
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +20 -15
- package/package.json +24 -2
- package/src/css/column-selector.css +3 -2
- package/src/css/column-settings-panel.css +44 -9
- package/src/css/column-style.css +35 -2
- package/src/css/containers/scroll-panel.css +2 -1
- package/src/css/containers/tabs.css +8 -52
- package/src/css/dom/checkbox.css +2 -6
- package/src/css/form/code-editor.css +1 -0
- package/src/css/form/debug.css +3 -10
- package/src/css/plugin-selector.css +33 -0
- package/src/css/plugin-settings-panel.css +99 -0
- package/src/css/viewer.css +143 -3
- package/src/rust/components/column_dropdown.rs +3 -1
- package/src/rust/components/column_selector/active_column.rs +16 -19
- package/src/rust/components/column_selector/config_selector.rs +20 -20
- package/src/rust/components/column_selector/filter_column.rs +14 -14
- package/src/rust/components/column_selector/inactive_column.rs +10 -15
- package/src/rust/components/column_selector/pivot_column.rs +7 -7
- package/src/rust/components/column_selector/sort_column.rs +7 -7
- package/src/rust/components/column_selector.rs +55 -37
- package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +15 -7
- package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +395 -0
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +15 -6
- package/src/rust/components/column_settings_sidebar/style_tab.rs +267 -136
- package/src/rust/components/column_settings_sidebar.rs +44 -49
- package/src/rust/components/containers/dragdrop_list.rs +32 -5
- package/src/rust/components/containers/mod.rs +0 -1
- package/src/rust/components/containers/scroll_panel.rs +21 -7
- package/src/rust/components/containers/sidebar.rs +8 -6
- package/src/rust/components/containers/split_panel.rs +3 -3
- package/src/rust/components/containers/tab_list.rs +3 -9
- package/src/rust/components/copy_dropdown.rs +2 -3
- package/src/rust/components/datetime_column_style.rs +19 -81
- package/src/rust/components/editable_header.rs +17 -3
- package/src/rust/components/export_dropdown.rs +2 -3
- package/src/rust/components/expression_editor.rs +29 -17
- package/src/rust/components/filter_dropdown.rs +2 -1
- package/src/rust/components/form/color_range_selector.rs +14 -7
- package/src/rust/components/form/debug.rs +47 -37
- package/src/rust/components/main_panel.rs +24 -65
- package/src/rust/components/mod.rs +2 -1
- package/src/rust/components/number_series_style.rs +161 -0
- package/src/rust/components/plugin_tab.rs +221 -0
- package/src/rust/components/settings_panel.rs +181 -59
- package/src/rust/components/status_bar.rs +141 -174
- package/src/rust/components/status_indicator.rs +15 -22
- package/src/rust/components/string_column_style.rs +20 -82
- package/src/rust/components/style_controls/number_string_format.rs +14 -30
- package/src/rust/components/viewer.rs +169 -132
- package/src/rust/config/column_config_schema.rs +195 -0
- package/src/rust/config/columns_config.rs +4 -97
- package/src/rust/config/datetime_column_style.rs +0 -5
- package/src/rust/config/mod.rs +8 -2
- package/src/rust/config/number_series_style.rs +79 -0
- package/src/rust/config/plugin_static_config.rs +144 -0
- package/src/rust/config/string_column_style.rs +0 -5
- package/src/rust/config/viewer_config.rs +5 -6
- package/src/rust/custom_elements/copy_dropdown.rs +30 -18
- package/src/rust/custom_elements/debug_plugin.rs +1 -3
- package/src/rust/custom_elements/export_dropdown.rs +26 -18
- package/src/rust/custom_elements/viewer.rs +62 -73
- package/src/rust/custom_events.rs +181 -224
- package/src/rust/js/plugin.rs +45 -117
- package/src/rust/lib.rs +34 -5
- package/src/rust/presentation/drag_helpers.rs +206 -0
- package/src/rust/presentation/props.rs +8 -0
- package/src/rust/presentation.rs +256 -41
- package/src/rust/{tasks → queries}/column_locator.rs +17 -73
- package/src/rust/queries/column_values.rs +59 -0
- package/src/rust/{tasks → queries}/columns_iter_set.rs +11 -18
- package/src/rust/queries/exports.rs +96 -0
- package/src/rust/queries/fetch_column_stats.rs +94 -0
- package/src/rust/queries/get_viewer_config.rs +54 -0
- package/src/rust/queries/mod.rs +44 -0
- package/src/rust/queries/plugin_column_styles.rs +101 -0
- package/src/rust/{engines.rs → queries/validate_expression.rs} +26 -15
- package/src/rust/renderer/activate.rs +1 -0
- package/src/rust/renderer/limits.rs +9 -4
- package/src/rust/renderer/plugin_store.rs +12 -0
- package/src/rust/renderer/props.rs +28 -3
- package/src/rust/renderer/registry.rs +40 -15
- package/src/rust/renderer.rs +703 -60
- package/src/rust/session/column_defaults_update.rs +20 -28
- package/src/rust/session/drag_drop_update.rs +10 -10
- package/src/rust/session/metadata.rs +31 -16
- package/src/rust/session/props.rs +15 -6
- package/src/rust/session/view_subscription.rs +10 -0
- package/src/rust/session.rs +109 -147
- package/src/rust/tasks/copy_export.rs +178 -158
- package/src/rust/tasks/{structural.rs → dismiss_render_warning.rs} +20 -40
- package/src/rust/tasks/edit_expression.rs +68 -88
- package/src/rust/tasks/eject.rs +25 -22
- package/src/rust/tasks/intersection_observer.rs +8 -21
- package/src/rust/tasks/mod.rs +19 -21
- package/src/rust/tasks/reset_all.rs +98 -0
- package/src/rust/tasks/resize_observer.rs +11 -33
- package/src/rust/tasks/restore_and_render.rs +128 -90
- package/src/rust/tasks/{get_viewer_config.rs → send_column_config.rs} +39 -35
- package/src/rust/tasks/send_plugin_config.rs +33 -33
- package/src/rust/tasks/update_and_render.rs +75 -49
- package/src/rust/{components/containers/trap_door_panel.rs → tasks/update_theme.rs} +34 -33
- package/src/rust/tasks/validate_expression.rs +61 -0
- package/src/rust/utils/browser/selection.rs +4 -4
- package/src/rust/utils/mod.rs +0 -63
- package/src/svg/checkbox-checked-icon.svg +1 -1
- package/src/svg/checkbox-unchecked-icon.svg +1 -1
- package/src/svg/mega-menu-icons-density.svg +23 -0
- package/src/svg/mega-menu-icons-map-density.svg +24 -0
- package/src/svg/mega-menu-icons-map-line.svg +19 -0
- package/src/themes/botanical.css +27 -53
- package/src/themes/defaults.css +24 -36
- package/src/themes/dracula.css +36 -54
- package/src/themes/gruvbox-dark.css +39 -59
- package/src/themes/gruvbox.css +16 -28
- package/src/themes/icons.css +5 -0
- package/src/themes/intl/de.css +43 -6
- package/src/themes/intl/es.css +43 -6
- package/src/themes/intl/fr.css +43 -6
- package/src/themes/intl/ja.css +43 -6
- package/src/themes/intl/pt.css +43 -6
- package/src/themes/intl/zh.css +43 -6
- package/src/themes/intl.css +38 -4
- package/src/themes/monokai.css +45 -61
- package/src/themes/phosphor.css +20 -29
- package/src/themes/pro-dark.css +25 -34
- package/src/themes/solarized-dark.css +21 -36
- package/src/themes/solarized.css +13 -23
- package/src/themes/vaporwave.css +40 -74
- package/src/ts/bootstrap.ts +14 -3
- package/src/ts/column-format.ts +162 -0
- package/src/ts/extensions.ts +4 -0
- package/src/ts/perspective-viewer.ts +9 -1
- package/src/{rust/components/column_settings_sidebar/style_tab/stub.rs → ts/perspective-viewer.worker.ts} +2 -22
- package/src/ts/plugin.ts +25 -101
- package/src/ts/ts-rs/{FormatUnit.ts → ColumnSelectMode.ts} +1 -1
- package/src/ts/ts-rs/PluginStaticConfig.ts +78 -0
- package/src/ts/ts-rs/ViewerConfig.ts +1 -2
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -3
- package/dist/esm/ts-rs/ColumnConfigValues.d.ts +0 -31
- package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +0 -1
- package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +0 -15
- package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +0 -18
- package/dist/esm/ts-rs/DatetimeColorMode.d.ts +0 -1
- package/dist/esm/ts-rs/DatetimeFormatType.d.ts +0 -6
- package/dist/esm/ts-rs/FormatMode.d.ts +0 -1
- package/dist/esm/ts-rs/FormatUnit.d.ts +0 -1
- package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +0 -1
- package/dist/esm/ts-rs/NumberForegroundMode.d.ts +0 -1
- package/dist/esm/ts-rs/PluginConfig.d.ts +0 -2
- package/dist/esm/ts-rs/RoundingMode.d.ts +0 -1
- package/dist/esm/ts-rs/RoundingPriority.d.ts +0 -1
- package/dist/esm/ts-rs/SignDisplay.d.ts +0 -1
- package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +0 -1
- package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +0 -6
- package/dist/esm/ts-rs/StringColorMode.d.ts +0 -1
- package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +0 -1
- package/dist/esm/ts-rs/UseGrouping.d.ts +0 -1
- package/src/rust/components/number_column_style.rs +0 -491
- package/src/rust/config/number_column_style.rs +0 -136
- package/src/rust/dragdrop.rs +0 -481
- package/src/rust/tasks/plugin_column_styles.rs +0 -98
- package/src/ts/ts-rs/ColumnConfigValues.ts +0 -14
- package/src/ts/ts-rs/CustomDatetimeFormat.ts +0 -3
- package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +0 -5
- package/src/ts/ts-rs/CustomNumberFormatConfig.ts +0 -8
- package/src/ts/ts-rs/DatetimeColorMode.ts +0 -3
- package/src/ts/ts-rs/DatetimeFormatType.ts +0 -8
- package/src/ts/ts-rs/FormatMode.ts +0 -3
- package/src/ts/ts-rs/NumberBackgroundMode.ts +0 -3
- package/src/ts/ts-rs/NumberForegroundMode.ts +0 -3
- package/src/ts/ts-rs/PluginConfig.ts +0 -4
- package/src/ts/ts-rs/RoundingMode.ts +0 -3
- package/src/ts/ts-rs/RoundingPriority.ts +0 -3
- package/src/ts/ts-rs/SignDisplay.ts +0 -3
- package/src/ts/ts-rs/SimpleDatetimeFormat.ts +0 -3
- package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +0 -4
- package/src/ts/ts-rs/StringColorMode.ts +0 -3
- package/src/ts/ts-rs/TrailingZeroDisplay.ts +0 -3
- package/src/ts/ts-rs/UseGrouping.ts +0 -3
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline4.js +0 -0
- /package/src/rust/{tasks → config}/export_method.rs +0 -0
- /package/src/rust/{tasks → queries}/export_app.rs +0 -0
- /package/src/rust/{tasks → queries}/is_invalid_drop.rs +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
mod attributes_tab;
|
|
13
13
|
|
|
14
14
|
mod save_settings;
|
|
15
|
-
mod style_tab;
|
|
15
|
+
pub(crate) mod style_tab;
|
|
16
16
|
|
|
17
17
|
use std::rc::Rc;
|
|
18
18
|
|
|
@@ -33,14 +33,10 @@ use crate::components::editable_header::EditableHeaderProps;
|
|
|
33
33
|
use crate::components::expression_editor::ExpressionEditorProps;
|
|
34
34
|
use crate::components::style::LocalStyle;
|
|
35
35
|
use crate::components::type_icon::TypeIconType;
|
|
36
|
-
use crate::custom_events::CustomEvents;
|
|
37
36
|
use crate::presentation::{ColumnLocator, ColumnSettingsTab, Presentation};
|
|
38
37
|
use crate::renderer::Renderer;
|
|
39
38
|
use crate::session::{Session, SessionMetadataRc};
|
|
40
|
-
use crate::tasks::{
|
|
41
|
-
EditExpression, HasCustomEvents, HasPresentation, HasRenderer, HasSession,
|
|
42
|
-
can_render_column_styles, locator_name_or_default, locator_view_type,
|
|
43
|
-
};
|
|
39
|
+
use crate::tasks::{delete_expr, save_expr, update_expr};
|
|
44
40
|
use crate::utils::PtrEqRc;
|
|
45
41
|
use crate::*;
|
|
46
42
|
|
|
@@ -64,13 +60,13 @@ pub struct ColumnSettingsPanelProps {
|
|
|
64
60
|
/// View config snapshot — threaded from `SessionProps`.
|
|
65
61
|
pub view_config: PtrEqRc<ViewConfig>,
|
|
66
62
|
|
|
63
|
+
/// Per-column stats snapshot — threaded from `SessionProps`.
|
|
64
|
+
pub column_stats: PtrEqRc<std::collections::HashMap<String, crate::session::ColumnStats>>,
|
|
65
|
+
|
|
67
66
|
/// Selected theme name, threaded for PortalModal consumers.
|
|
68
67
|
pub selected_theme: Option<String>,
|
|
69
68
|
|
|
70
69
|
// State
|
|
71
|
-
#[derivative(Debug = "ignore")]
|
|
72
|
-
pub custom_events: CustomEvents,
|
|
73
|
-
|
|
74
70
|
#[derivative(Debug = "ignore")]
|
|
75
71
|
pub presentation: Presentation,
|
|
76
72
|
|
|
@@ -88,34 +84,11 @@ impl PartialEq for ColumnSettingsPanelProps {
|
|
|
88
84
|
&& self.plugin_name == other.plugin_name
|
|
89
85
|
&& self.metadata == other.metadata
|
|
90
86
|
&& self.view_config == other.view_config
|
|
87
|
+
&& self.column_stats == other.column_stats
|
|
91
88
|
&& self.selected_theme == other.selected_theme
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
91
|
|
|
95
|
-
impl HasCustomEvents for ColumnSettingsPanelProps {
|
|
96
|
-
fn custom_events(&self) -> &CustomEvents {
|
|
97
|
-
&self.custom_events
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
impl HasPresentation for ColumnSettingsPanelProps {
|
|
102
|
-
fn presentation(&self) -> &Presentation {
|
|
103
|
-
&self.presentation
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
impl HasRenderer for ColumnSettingsPanelProps {
|
|
108
|
-
fn renderer(&self) -> &Renderer {
|
|
109
|
-
&self.renderer
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
impl HasSession for ColumnSettingsPanelProps {
|
|
114
|
-
fn session(&self) -> &Session {
|
|
115
|
-
&self.session
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
92
|
#[derive(Debug)]
|
|
120
93
|
pub enum ColumnSettingsPanelMsg {
|
|
121
94
|
SetExprValue(Rc<String>),
|
|
@@ -239,11 +212,20 @@ impl Component for ColumnSettingsPanel {
|
|
|
239
212
|
ColumnLocator::Table(_) => {
|
|
240
213
|
tracing::error!("Tried to save non-expression column!")
|
|
241
214
|
},
|
|
242
|
-
ColumnLocator::Expression(name) =>
|
|
243
|
-
ctx.props().
|
|
244
|
-
|
|
215
|
+
ColumnLocator::Expression(name) => update_expr(
|
|
216
|
+
&ctx.props().session,
|
|
217
|
+
&ctx.props().renderer,
|
|
218
|
+
&ctx.props().presentation,
|
|
219
|
+
name.clone(),
|
|
220
|
+
new_expr,
|
|
221
|
+
),
|
|
245
222
|
ColumnLocator::NewExpression => {
|
|
246
|
-
if let Err(err) =
|
|
223
|
+
if let Err(err) = save_expr(
|
|
224
|
+
&ctx.props().session,
|
|
225
|
+
&ctx.props().renderer,
|
|
226
|
+
&ctx.props().presentation,
|
|
227
|
+
new_expr,
|
|
228
|
+
) {
|
|
247
229
|
tracing::warn!("{}", err);
|
|
248
230
|
}
|
|
249
231
|
},
|
|
@@ -258,7 +240,12 @@ impl Component for ColumnSettingsPanel {
|
|
|
258
240
|
},
|
|
259
241
|
ColumnSettingsPanelMsg::OnDelete(()) => {
|
|
260
242
|
if ctx.props().selected_column.is_saved_expr() {
|
|
261
|
-
|
|
243
|
+
delete_expr(
|
|
244
|
+
&ctx.props().session,
|
|
245
|
+
&ctx.props().renderer,
|
|
246
|
+
&self.column_name,
|
|
247
|
+
)
|
|
248
|
+
.unwrap_or_log();
|
|
262
249
|
}
|
|
263
250
|
|
|
264
251
|
ctx.props().on_close.emit(());
|
|
@@ -277,6 +264,7 @@ impl Component for ColumnSettingsPanel {
|
|
|
277
264
|
ctx.props().selected_tab,
|
|
278
265
|
Some(ColumnSettingsTab::Attributes)
|
|
279
266
|
),
|
|
267
|
+
update_on_input: true,
|
|
280
268
|
icon_type: self
|
|
281
269
|
.maybe_ty
|
|
282
270
|
.map(|ty| ty.into())
|
|
@@ -347,8 +335,8 @@ impl Component for ColumnSettingsPanel {
|
|
|
347
335
|
group_by_depth: ctx.props().view_config.group_by.len() as u32,
|
|
348
336
|
view_config: ctx.props().view_config.clone(),
|
|
349
337
|
metadata: ctx.props().metadata.clone(),
|
|
338
|
+
column_stats: ctx.props().column_stats.clone(),
|
|
350
339
|
selected_theme: ctx.props().selected_theme.clone(),
|
|
351
|
-
custom_events: ctx.props().custom_events.clone(),
|
|
352
340
|
presentation: ctx.props().presentation.clone(),
|
|
353
341
|
renderer: ctx.props().renderer.clone(),
|
|
354
342
|
session: ctx.props().session.clone(),
|
|
@@ -398,8 +386,10 @@ impl ColumnSettingsPanel {
|
|
|
398
386
|
}
|
|
399
387
|
|
|
400
388
|
fn initialize(&mut self, ctx: &yew::prelude::Context<Self>) {
|
|
401
|
-
let column_name =
|
|
402
|
-
|
|
389
|
+
let column_name = ctx
|
|
390
|
+
.props()
|
|
391
|
+
.metadata
|
|
392
|
+
.locator_name_or_default(&ctx.props().selected_column);
|
|
403
393
|
|
|
404
394
|
let initial_expr_value = ctx
|
|
405
395
|
.props()
|
|
@@ -411,19 +401,23 @@ impl ColumnSettingsPanel {
|
|
|
411
401
|
let initial_header_value =
|
|
412
402
|
(*initial_expr_value != column_name).then_some(column_name.clone());
|
|
413
403
|
|
|
414
|
-
let maybe_ty =
|
|
404
|
+
let maybe_ty = ctx
|
|
405
|
+
.props()
|
|
406
|
+
.metadata
|
|
407
|
+
.locator_view_type(&ctx.props().selected_column);
|
|
415
408
|
|
|
416
409
|
let tabs = {
|
|
417
410
|
let mut tabs = vec![];
|
|
418
411
|
let is_new_expr = ctx.props().selected_column.is_new_expr();
|
|
419
412
|
let show_styles = !is_new_expr
|
|
420
|
-
&& can_render_column_styles(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
413
|
+
&& ctx.props().renderer.can_render_column_styles()
|
|
414
|
+
&& ctx.props().view_config.columns.contains(&Some(
|
|
415
|
+
ctx.props()
|
|
416
|
+
.selected_column
|
|
417
|
+
.name()
|
|
418
|
+
.map(|x| x.to_string())
|
|
419
|
+
.unwrap_or_default(),
|
|
420
|
+
));
|
|
427
421
|
|
|
428
422
|
if !is_new_expr && show_styles {
|
|
429
423
|
tabs.push(ColumnSettingsTab::Style);
|
|
@@ -432,6 +426,7 @@ impl ColumnSettingsPanel {
|
|
|
432
426
|
if ctx.props().selected_column.is_expr() {
|
|
433
427
|
tabs.push(ColumnSettingsTab::Attributes);
|
|
434
428
|
}
|
|
429
|
+
|
|
435
430
|
tabs
|
|
436
431
|
};
|
|
437
432
|
|
|
@@ -22,7 +22,7 @@ use yew::prelude::*;
|
|
|
22
22
|
use crate::components::column_dropdown::ColumnDropDownElement;
|
|
23
23
|
use crate::components::column_selector::{EmptyColumn, InPlaceColumn, InvalidColumn};
|
|
24
24
|
use crate::components::type_icon::TypeIcon;
|
|
25
|
-
use crate::
|
|
25
|
+
use crate::presentation::{DragDropContainer, Presentation};
|
|
26
26
|
use crate::utils::DragTarget;
|
|
27
27
|
|
|
28
28
|
#[derive(Properties, Derivative)]
|
|
@@ -35,7 +35,7 @@ where
|
|
|
35
35
|
{
|
|
36
36
|
pub parent: Scope<T>,
|
|
37
37
|
|
|
38
|
-
pub
|
|
38
|
+
pub presentation: Presentation,
|
|
39
39
|
pub name: &'static str,
|
|
40
40
|
pub column_dropdown: ColumnDropDownElement,
|
|
41
41
|
pub exclude: HashSet<String>,
|
|
@@ -185,14 +185,20 @@ where
|
|
|
185
185
|
);
|
|
186
186
|
|
|
187
187
|
let drop = Callback::from({
|
|
188
|
-
let
|
|
188
|
+
let presentation = ctx.props().presentation.clone();
|
|
189
189
|
let link = ctx.link().clone();
|
|
190
190
|
move |event| {
|
|
191
191
|
link.send_message(DragDropListMsg::Freeze(false));
|
|
192
|
-
|
|
192
|
+
presentation.notify_drop(&event);
|
|
193
193
|
}
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
+
// Held by per-row `ondragenter` closures below so they can re-arm
|
|
197
|
+
// the `safaridragleave` flag on the container element when the
|
|
198
|
+
// row stops dragenter from bubbling. See the comment inside the
|
|
199
|
+
// closure for why this matters.
|
|
200
|
+
let container_noderef = drag_container.noderef.clone();
|
|
201
|
+
|
|
196
202
|
let invalid_drag: bool;
|
|
197
203
|
let mut valid_duplicate_drag = false;
|
|
198
204
|
|
|
@@ -210,7 +216,7 @@ where
|
|
|
210
216
|
let is_append = index == columns.len();
|
|
211
217
|
let is_self_move = ctx
|
|
212
218
|
.props()
|
|
213
|
-
.
|
|
219
|
+
.presentation
|
|
214
220
|
.get_drag_target()
|
|
215
221
|
.map(|x| V::is_self_move(x))
|
|
216
222
|
.unwrap_or_default();
|
|
@@ -253,9 +259,30 @@ where
|
|
|
253
259
|
let close = ctx.props().parent.callback(move |_| V::close(idx));
|
|
254
260
|
let dragenter = ctx.props().parent.callback({
|
|
255
261
|
let link = ctx.link().clone();
|
|
262
|
+
let container_noderef = container_noderef.clone();
|
|
256
263
|
move |event: DragEvent| {
|
|
257
264
|
event.stop_propagation();
|
|
258
265
|
event.prevent_default();
|
|
266
|
+
// Safari: `relatedTarget` is always null on
|
|
267
|
+
// dragleave, so `dragleave_helper` uses a
|
|
268
|
+
// `data-safaridragleave` flag set by the
|
|
269
|
+
// container's own dragenter to distinguish
|
|
270
|
+
// child-crossing leaves (consume the flag)
|
|
271
|
+
// from real leaves (no flag → fire callback).
|
|
272
|
+
// The `stop_propagation` above blocks the
|
|
273
|
+
// container's dragenter, so the flag would
|
|
274
|
+
// never be re-armed after the first consume —
|
|
275
|
+
// any further internal boundary crossing
|
|
276
|
+
// would demote the state out of
|
|
277
|
+
// `DragOverInProgress` and the next drop
|
|
278
|
+
// would be silently rejected. Set the flag
|
|
279
|
+
// here so each row-targeted dragenter
|
|
280
|
+
// refills the pool.
|
|
281
|
+
if event.related_target().is_none()
|
|
282
|
+
&& let Some(elem) = container_noderef.cast::<HtmlElement>()
|
|
283
|
+
{
|
|
284
|
+
let _ = elem.dataset().set("safaridragleave", "true");
|
|
285
|
+
}
|
|
259
286
|
link.send_message(DragDropListMsg::Freeze(true));
|
|
260
287
|
V::dragenter(idx)
|
|
261
288
|
}
|
|
@@ -63,6 +63,9 @@ pub struct ScrollPanelProps {
|
|
|
63
63
|
|
|
64
64
|
#[prop_or_default]
|
|
65
65
|
pub drop: Callback<DragEvent>,
|
|
66
|
+
|
|
67
|
+
#[prop_or_default]
|
|
68
|
+
pub omit_autosize_div: bool,
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
impl ScrollPanelProps {
|
|
@@ -146,16 +149,25 @@ impl Component for ScrollPanel {
|
|
|
146
149
|
self.viewport_width = 0.0;
|
|
147
150
|
self.calculate_window_content(ctx)
|
|
148
151
|
},
|
|
152
|
+
|
|
153
|
+
// TODO don't hardcode pixel offsets - fix the CSS container to not
|
|
154
|
+
// require pixel offsets to work.
|
|
149
155
|
ScrollPanelMsg::UpdateViewportDimensions => {
|
|
150
156
|
let viewport = self.viewport_elem(ctx);
|
|
151
157
|
let rect = viewport.get_bounding_client_rect();
|
|
152
158
|
let viewport_height = rect.height() - 8.0;
|
|
153
|
-
let
|
|
159
|
+
let scroll_offset = if ctx.props().omit_autosize_div {
|
|
160
|
+
0.0
|
|
161
|
+
} else {
|
|
162
|
+
6.0
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
let viewport_width = self.viewport_width.max(rect.width() - scroll_offset);
|
|
154
166
|
let re_render = self.viewport_height != viewport_height
|
|
155
167
|
|| self.viewport_width != viewport_width;
|
|
156
168
|
|
|
157
169
|
self.viewport_height = rect.height() - 8.0;
|
|
158
|
-
self.viewport_width = self.viewport_width.max(rect.width() -
|
|
170
|
+
self.viewport_width = self.viewport_width.max(rect.width() - scroll_offset);
|
|
159
171
|
ctx.props().on_auto_width.emit(self.viewport_width);
|
|
160
172
|
re_render
|
|
161
173
|
},
|
|
@@ -218,11 +230,13 @@ impl Component for ScrollPanel {
|
|
|
218
230
|
>
|
|
219
231
|
<div class="scroll-panel-container" style={window_style}>
|
|
220
232
|
{ for windowed_items.iter().cloned().map(Html::from) }
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
233
|
+
if !ctx.props().omit_autosize_div {
|
|
234
|
+
<div
|
|
235
|
+
key="__scroll-panel-auto-width__"
|
|
236
|
+
class="scroll-panel-auto-width"
|
|
237
|
+
style={width_style}
|
|
238
|
+
/>
|
|
239
|
+
}
|
|
226
240
|
</div>
|
|
227
241
|
<div class="scroll-panel-content" style={content_style} />
|
|
228
242
|
</div>
|
|
@@ -62,12 +62,14 @@ pub fn Sidebar(p: &SidebarProps) -> Html {
|
|
|
62
62
|
|
|
63
63
|
let width_style = format!("min-width: 200px; width: {}px", *auto_width);
|
|
64
64
|
html! {
|
|
65
|
-
|
|
65
|
+
<>
|
|
66
66
|
<SidebarCloseButton id={format!("{id}_close_button")} on_close_sidebar={&p.on_close} />
|
|
67
|
-
<div class="
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
<div class="sidebar_column" id={format!("{id}_sidebar")} ref={noderef}>
|
|
68
|
+
<div class="sidebar_header"><EditableHeader ..p.header_props.clone() /></div>
|
|
69
|
+
<div class="sidebar_border" id={format!("{id}_border")} />
|
|
70
|
+
{ p.children.iter().collect::<Html>() }
|
|
71
|
+
<div class="sidebar-auto-width" style={width_style} />
|
|
72
|
+
</div>
|
|
73
|
+
</>
|
|
72
74
|
}
|
|
73
75
|
}
|
|
@@ -20,7 +20,7 @@ use yew::html::Scope;
|
|
|
20
20
|
use yew::prelude::*;
|
|
21
21
|
|
|
22
22
|
use crate::components::style::LocalStyle;
|
|
23
|
-
use crate::
|
|
23
|
+
use crate::css;
|
|
24
24
|
|
|
25
25
|
#[derive(Properties, Default)]
|
|
26
26
|
pub struct SplitPanelProps {
|
|
@@ -359,14 +359,14 @@ impl Drop for ResizingState {
|
|
|
359
359
|
/// `body`. Without this, the `Closure` objects would not leak, but the
|
|
360
360
|
/// document will continue to call them, causing runtime exceptions.
|
|
361
361
|
fn drop(&mut self) {
|
|
362
|
-
let result: ApiResult<()> =
|
|
362
|
+
let result: ApiResult<()> = (|| {
|
|
363
363
|
let mousemove = self.mousemove.as_ref().unchecked_ref();
|
|
364
364
|
global::body().remove_event_listener_with_callback("mousemove", mousemove)?;
|
|
365
365
|
let mouseup = self.mouseup.as_ref().unchecked_ref();
|
|
366
366
|
global::body().remove_event_listener_with_callback("mouseup", mouseup)?;
|
|
367
367
|
self.release_cursor()?;
|
|
368
368
|
Ok(())
|
|
369
|
-
};
|
|
369
|
+
})();
|
|
370
370
|
|
|
371
371
|
result.expect("Drop failed")
|
|
372
372
|
}
|
|
@@ -71,9 +71,9 @@ impl<T: ColumnTab> Component for TabList<T> {
|
|
|
71
71
|
fn view(&self, ctx: &yew::Context<Self>) -> Html {
|
|
72
72
|
let p = ctx.props();
|
|
73
73
|
let gutter_tabs = p.tabs.iter().enumerate().map(|(idx, tab)| {
|
|
74
|
-
let mut class = classes!("
|
|
74
|
+
let mut class = classes!("settings_tab");
|
|
75
75
|
if idx == self.selected_idx {
|
|
76
|
-
class.push("
|
|
76
|
+
class.push("selected_tab");
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
let onclick = ctx.link().callback(move |_| TabListMsg::SetSelected(idx));
|
|
@@ -88,13 +88,7 @@ impl<T: ColumnTab> Component for TabList<T> {
|
|
|
88
88
|
html! {
|
|
89
89
|
<>
|
|
90
90
|
<LocalStyle href={css!("containers/tabs")} />
|
|
91
|
-
<div
|
|
92
|
-
{ for gutter_tabs }
|
|
93
|
-
<span class="tab tab-padding">
|
|
94
|
-
<div class="tab-title">{ "\u{00a0}" }</div>
|
|
95
|
-
<div class="tab-border" />
|
|
96
|
-
</span>
|
|
97
|
-
</div>
|
|
91
|
+
<div id="settings_tab_bar">{ for gutter_tabs }</div>
|
|
98
92
|
<div id="format-tab" class="tab-content scrollable">
|
|
99
93
|
{ ctx.props().children.iter().nth(self.selected_idx) }
|
|
100
94
|
</div>
|
|
@@ -15,8 +15,8 @@ use std::rc::Rc;
|
|
|
15
15
|
use yew::prelude::*;
|
|
16
16
|
|
|
17
17
|
use super::containers::dropdown_menu::*;
|
|
18
|
+
use crate::config::*;
|
|
18
19
|
use crate::renderer::*;
|
|
19
|
-
use crate::tasks::*;
|
|
20
20
|
|
|
21
21
|
type CopyDropDownMenuItem = DropDownMenuItem<ExportFile>;
|
|
22
22
|
|
|
@@ -41,8 +41,7 @@ impl Component for CopyDropDownMenu {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
fn view(&self, ctx: &Context<Self>) -> yew::virtual_dom::VNode {
|
|
44
|
-
let
|
|
45
|
-
let is_chart = plugin.name().as_str() != "Datagrid";
|
|
44
|
+
let is_chart = ctx.props().renderer.is_chart();
|
|
46
45
|
let has_selection = ctx.props().renderer.get_selection().is_some();
|
|
47
46
|
html! {
|
|
48
47
|
<>
|
|
@@ -21,28 +21,30 @@ use perspective_js::json;
|
|
|
21
21
|
use perspective_js::utils::global::navigator;
|
|
22
22
|
use wasm_bindgen::prelude::*;
|
|
23
23
|
use yew::prelude::*;
|
|
24
|
-
use yew::*;
|
|
25
24
|
|
|
26
|
-
use super::form::color_selector::*;
|
|
27
25
|
use super::modal::{ModalLink, SetModalLink};
|
|
28
26
|
use super::style::LocalStyle;
|
|
29
27
|
use crate::components::datetime_column_style::custom::DatetimeStyleCustom;
|
|
30
28
|
use crate::components::datetime_column_style::simple::DatetimeStyleSimple;
|
|
31
|
-
use crate::components::form::select_enum_field::SelectEnumField;
|
|
32
29
|
use crate::components::form::select_value_field::SelectValueField;
|
|
33
30
|
use crate::config::*;
|
|
34
31
|
use crate::css;
|
|
35
32
|
use crate::utils::WeakScope;
|
|
36
33
|
|
|
34
|
+
/// Format-only widget for `datetime` columns. Renders the `date_format`
|
|
35
|
+
/// hierarchy (Simple|Custom + timezone); color/color-mode UI is provided
|
|
36
|
+
/// externally as primitive `Enum` + `Color` schema fields.
|
|
37
37
|
#[derive(Properties, Derivative)]
|
|
38
38
|
#[derivative(Debug)]
|
|
39
39
|
pub struct DatetimeColumnStyleProps {
|
|
40
40
|
pub enable_time_config: bool,
|
|
41
41
|
pub config: Option<DatetimeColumnStyleConfig>,
|
|
42
|
-
pub default_config: DatetimeColumnStyleDefaultConfig,
|
|
43
42
|
|
|
44
43
|
#[prop_or_default]
|
|
45
|
-
pub on_change: Callback<
|
|
44
|
+
pub on_change: Callback<ColumnConfigFieldUpdate>,
|
|
45
|
+
|
|
46
|
+
#[prop_or_default]
|
|
47
|
+
pub keys: Vec<String>,
|
|
46
48
|
|
|
47
49
|
#[prop_or_default]
|
|
48
50
|
#[derivative(Debug = "ignore")]
|
|
@@ -57,9 +59,7 @@ impl ModalLink<DatetimeColumnStyle> for DatetimeColumnStyleProps {
|
|
|
57
59
|
|
|
58
60
|
impl PartialEq for DatetimeColumnStyleProps {
|
|
59
61
|
fn eq(&self, other: &Self) -> bool {
|
|
60
|
-
self.enable_time_config == other.enable_time_config
|
|
61
|
-
&& self.config == other.config
|
|
62
|
-
&& self.default_config == other.default_config
|
|
62
|
+
self.enable_time_config == other.enable_time_config && self.config == other.config
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -67,16 +67,11 @@ pub enum DatetimeColumnStyleMsg {
|
|
|
67
67
|
SimpleDatetimeStyleConfigChanged(SimpleDatetimeStyleConfig),
|
|
68
68
|
CustomDatetimeStyleConfigChanged(CustomDatetimeStyleConfig),
|
|
69
69
|
TimezoneChanged(Option<String>),
|
|
70
|
-
ColorModeChanged(Option<DatetimeColorMode>),
|
|
71
|
-
ColorChanged(String),
|
|
72
|
-
ColorReset,
|
|
73
70
|
}
|
|
74
71
|
|
|
75
|
-
/// Column style controls for the `datetime` type.
|
|
76
72
|
#[derive(Debug)]
|
|
77
73
|
pub struct DatetimeColumnStyle {
|
|
78
74
|
config: DatetimeColumnStyleConfig,
|
|
79
|
-
default_config: DatetimeColumnStyleDefaultConfig,
|
|
80
75
|
}
|
|
81
76
|
|
|
82
77
|
impl Component for DatetimeColumnStyle {
|
|
@@ -87,11 +82,9 @@ impl Component for DatetimeColumnStyle {
|
|
|
87
82
|
ctx.set_modal_link();
|
|
88
83
|
Self {
|
|
89
84
|
config: ctx.props().config.clone().unwrap_or_default(),
|
|
90
|
-
default_config: ctx.props().default_config.clone(),
|
|
91
85
|
}
|
|
92
86
|
}
|
|
93
87
|
|
|
94
|
-
// Always re-render when config changes.
|
|
95
88
|
fn changed(&mut self, ctx: &Context<Self>, old: &Self::Properties) -> bool {
|
|
96
89
|
let mut rerender = false;
|
|
97
90
|
let mut new_config = ctx.props().config.clone().unwrap_or_default();
|
|
@@ -105,7 +98,6 @@ impl Component for DatetimeColumnStyle {
|
|
|
105
98
|
rerender
|
|
106
99
|
}
|
|
107
100
|
|
|
108
|
-
// TODO could be more conservative here with re-rendering
|
|
109
101
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
110
102
|
match msg {
|
|
111
103
|
DatetimeColumnStyleMsg::TimezoneChanged(val) => {
|
|
@@ -118,17 +110,6 @@ impl Component for DatetimeColumnStyle {
|
|
|
118
110
|
self.dispatch_config(ctx);
|
|
119
111
|
true
|
|
120
112
|
},
|
|
121
|
-
DatetimeColumnStyleMsg::ColorModeChanged(mode) => {
|
|
122
|
-
self.config.datetime_color_mode = mode.unwrap_or_default();
|
|
123
|
-
self.dispatch_config(ctx);
|
|
124
|
-
true
|
|
125
|
-
},
|
|
126
|
-
DatetimeColumnStyleMsg::ColorChanged(color) => {
|
|
127
|
-
self.config.color = Some(color);
|
|
128
|
-
self.dispatch_config(ctx);
|
|
129
|
-
true
|
|
130
|
-
},
|
|
131
|
-
|
|
132
113
|
DatetimeColumnStyleMsg::SimpleDatetimeStyleConfigChanged(simple) => {
|
|
133
114
|
self.config.date_format = DatetimeFormatType::Simple(simple);
|
|
134
115
|
self.dispatch_config(ctx);
|
|
@@ -139,40 +120,14 @@ impl Component for DatetimeColumnStyle {
|
|
|
139
120
|
self.dispatch_config(ctx);
|
|
140
121
|
true
|
|
141
122
|
},
|
|
142
|
-
DatetimeColumnStyleMsg::ColorReset => {
|
|
143
|
-
self.config.color = Some(self.default_config.color.clone());
|
|
144
|
-
self.dispatch_config(ctx);
|
|
145
|
-
true
|
|
146
|
-
},
|
|
147
123
|
}
|
|
148
124
|
}
|
|
149
125
|
|
|
150
126
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
151
|
-
let selected_color_mode = self.config.datetime_color_mode;
|
|
152
|
-
let color_mode_changed = ctx
|
|
153
|
-
.link()
|
|
154
|
-
.callback(DatetimeColumnStyleMsg::ColorModeChanged);
|
|
155
|
-
|
|
156
|
-
let color_controls = match selected_color_mode {
|
|
157
|
-
DatetimeColorMode::None => html! {},
|
|
158
|
-
DatetimeColorMode::Foreground => {
|
|
159
|
-
self.color_select_row(ctx, &DatetimeColorMode::Foreground, "foreground-label")
|
|
160
|
-
},
|
|
161
|
-
DatetimeColorMode::Background => {
|
|
162
|
-
self.color_select_row(ctx, &DatetimeColorMode::Background, "background-label")
|
|
163
|
-
},
|
|
164
|
-
};
|
|
165
|
-
|
|
166
127
|
html! {
|
|
167
128
|
<>
|
|
168
129
|
<LocalStyle href={css!("column-style")} />
|
|
169
130
|
<div id="column-style-container" class="datetime-column-style-container">
|
|
170
|
-
<SelectEnumField<DatetimeColorMode>
|
|
171
|
-
label="color"
|
|
172
|
-
on_change={color_mode_changed}
|
|
173
|
-
current_value={selected_color_mode}
|
|
174
|
-
/>
|
|
175
|
-
{ color_controls }
|
|
176
131
|
if ctx.props().enable_time_config {
|
|
177
132
|
<SelectValueField<String>
|
|
178
133
|
label="timezone"
|
|
@@ -251,35 +206,18 @@ static USER_TIMEZONE: LazyLock<String> = LazyLock::new(|| {
|
|
|
251
206
|
impl DatetimeColumnStyle {
|
|
252
207
|
/// When this config has changed, we must signal the wrapper element.
|
|
253
208
|
fn dispatch_config(&self, ctx: &Context<Self>) {
|
|
254
|
-
let
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
/// variant.
|
|
263
|
-
fn color_select_row(&self, ctx: &Context<Self>, mode: &DatetimeColorMode, title: &str) -> Html {
|
|
264
|
-
let on_color = ctx.link().callback(DatetimeColumnStyleMsg::ColorChanged);
|
|
265
|
-
let color = self
|
|
266
|
-
.config
|
|
267
|
-
.color
|
|
268
|
-
.clone()
|
|
269
|
-
.unwrap_or_else(|| self.default_config.color.to_owned());
|
|
209
|
+
let value = if self.config == DatetimeColumnStyleConfig::default() {
|
|
210
|
+
serde_json::Map::new()
|
|
211
|
+
} else {
|
|
212
|
+
match serde_json::to_value(&self.config) {
|
|
213
|
+
Ok(serde_json::Value::Object(m)) => m,
|
|
214
|
+
_ => serde_json::Map::new(),
|
|
215
|
+
}
|
|
216
|
+
};
|
|
270
217
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
is_modified: color != self.default_config.color,
|
|
275
|
-
color,
|
|
276
|
-
on_reset: ctx.link().callback(|_| DatetimeColumnStyleMsg::ColorReset)
|
|
218
|
+
ctx.props().on_change.emit(ColumnConfigFieldUpdate {
|
|
219
|
+
keys: ctx.props().keys.clone(),
|
|
220
|
+
value,
|
|
277
221
|
});
|
|
278
|
-
|
|
279
|
-
if &self.config.datetime_color_mode == mode {
|
|
280
|
-
html! { <div class="row"><ColorSelector ..color_props /></div> }
|
|
281
|
-
} else {
|
|
282
|
-
html! {}
|
|
283
|
-
}
|
|
284
222
|
}
|
|
285
223
|
}
|
|
@@ -18,7 +18,6 @@ use yew::{Callback, Component, Html, NodeRef, Properties, TargetCast, classes, h
|
|
|
18
18
|
|
|
19
19
|
use super::type_icon::TypeIconType;
|
|
20
20
|
use crate::components::type_icon::TypeIcon;
|
|
21
|
-
use crate::maybe;
|
|
22
21
|
use crate::session::{Session, SessionMetadataRc};
|
|
23
22
|
|
|
24
23
|
#[derive(Clone, PartialEq, Properties)]
|
|
@@ -29,9 +28,13 @@ pub struct EditableHeaderProps {
|
|
|
29
28
|
pub initial_value: Option<String>,
|
|
30
29
|
pub placeholder: Rc<String>,
|
|
31
30
|
|
|
31
|
+
// TODO remove this pattern
|
|
32
32
|
#[prop_or_default]
|
|
33
33
|
pub reset_count: u8,
|
|
34
34
|
|
|
35
|
+
#[prop_or_default]
|
|
36
|
+
pub update_on_input: bool,
|
|
37
|
+
|
|
35
38
|
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
36
39
|
pub metadata: SessionMetadataRc,
|
|
37
40
|
|
|
@@ -103,7 +106,7 @@ impl Component for EditableHeader {
|
|
|
103
106
|
let maybe_value = (!new_value.is_empty()).then_some(new_value.clone());
|
|
104
107
|
self.edited = ctx.props().initial_value != maybe_value;
|
|
105
108
|
|
|
106
|
-
self.valid =
|
|
109
|
+
self.valid = (|| -> Option<bool> {
|
|
107
110
|
if maybe_value
|
|
108
111
|
.as_ref()
|
|
109
112
|
.map(|v| v == &self.placeholder)
|
|
@@ -122,7 +125,7 @@ impl Component for EditableHeader {
|
|
|
122
125
|
.chain(expressions)
|
|
123
126
|
.contains(&new_value);
|
|
124
127
|
Some(!found)
|
|
125
|
-
})
|
|
128
|
+
})()
|
|
126
129
|
.unwrap_or(true);
|
|
127
130
|
|
|
128
131
|
self.value.clone_from(&maybe_value);
|
|
@@ -164,6 +167,16 @@ impl Component for EditableHeader {
|
|
|
164
167
|
EditableHeaderMsg::SetNewValue(value)
|
|
165
168
|
});
|
|
166
169
|
|
|
170
|
+
let update_on_input = ctx.props().update_on_input;
|
|
171
|
+
let oninput = ctx.link().batch_callback(move |e: yew::InputEvent| {
|
|
172
|
+
if update_on_input {
|
|
173
|
+
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
|
174
|
+
vec![EditableHeaderMsg::SetNewValue(value)]
|
|
175
|
+
} else {
|
|
176
|
+
vec![]
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
167
180
|
html! {
|
|
168
181
|
<div class={classes} onclick={ctx.link().callback(|_| EditableHeaderMsg::OnClick(()))}>
|
|
169
182
|
if let Some(icon) = ctx.props().icon_type { <TypeIcon ty={icon} /> }
|
|
@@ -174,6 +187,7 @@ impl Component for EditableHeader {
|
|
|
174
187
|
disabled={!ctx.props().editable}
|
|
175
188
|
{onblur}
|
|
176
189
|
{onkeyup}
|
|
190
|
+
{oninput}
|
|
177
191
|
value={self.value.clone()}
|
|
178
192
|
placeholder={self.placeholder.clone()}
|
|
179
193
|
/>
|