@perspective-dev/viewer 5.2.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.
- package/dist/cdn/perspective-viewer.js +8 -8
- package/dist/cdn/perspective-viewer.js.map +3 -3
- package/dist/css/blueprint.css +1 -0
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/eggplant.css +1 -0
- 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/ledger.css +1 -0
- package/dist/css/monokai.css +1 -1
- package/dist/css/nord.css +1 -0
- 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/css/velvet.css +1 -0
- package/dist/docs/perspective-docs.json +1 -1
- package/dist/esm/column-format.d.ts +16 -3
- package/dist/esm/perspective-viewer.d.ts +1 -0
- package/dist/esm/perspective-viewer.inline.js +9 -9
- package/dist/esm/perspective-viewer.inline.js.map +3 -3
- package/dist/esm/perspective-viewer.js +8 -8
- package/dist/esm/perspective-viewer.js.map +3 -3
- package/dist/esm/plugin.d.ts +10 -0
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +1 -1
- package/dist/esm/ts-rs/SaveWorkspaceOptions.d.ts +10 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +1 -1
- package/dist/esm/ts-rs/WorkspaceConfig.d.ts +9 -1
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +13 -3
- package/dist/wasm/perspective-viewer.d.ts +43 -36
- package/dist/wasm/perspective-viewer.js +198 -136
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +19 -17
- package/package.json +1 -1
- package/src/css/column-settings-panel.css +28 -5
- package/src/css/column-style.css +291 -31
- package/src/css/containers/tabs.css +13 -3
- package/src/css/dom/select.css +21 -9
- package/src/css/form/code-editor.css +4 -4
- package/src/css/plugin-selector.css +1 -0
- package/src/css/plugin-settings-panel.css +72 -0
- package/src/css/viewer.css +0 -5
- package/src/rust/agent/tools.rs +53 -19
- package/src/rust/components/column_selector/active_column.rs +2 -2
- package/src/rust/components/column_selector/add_expression_button.rs +3 -3
- package/src/rust/components/column_selector/aggregate_selector.rs +2 -3
- package/src/rust/components/column_selector/config_selector.rs +8 -0
- package/src/rust/components/column_selector/expr_edit_button.rs +4 -10
- package/src/rust/components/column_selector/inactive_column.rs +2 -2
- package/src/rust/components/column_selector.rs +48 -4
- package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +293 -126
- package/src/rust/components/column_settings_sidebar/style_tab.rs +330 -234
- package/src/rust/components/column_settings_sidebar.rs +88 -69
- package/src/rust/components/containers/control_group.rs +91 -0
- package/src/rust/components/containers/mod.rs +1 -0
- package/src/rust/components/containers/select.rs +8 -2
- package/src/rust/components/datetime_column_style/simple.rs +15 -4
- package/src/rust/components/datetime_column_style.rs +50 -10
- package/src/rust/components/editable_header.rs +85 -144
- package/src/rust/components/expression_editor.rs +9 -16
- package/src/rust/components/form/code_editor.rs +16 -6
- package/src/rust/components/form/debug.rs +1 -0
- package/src/rust/components/form/mod.rs +3 -1
- package/src/rust/components/form/multi_stop_gradient_selector.rs +476 -0
- package/src/rust/components/form/named_value_picker.rs +86 -0
- package/src/rust/components/form/palette_selector.rs +440 -0
- package/src/rust/components/main_panel/msg.rs +2 -2
- package/src/rust/components/main_panel/reconcile.rs +4 -4
- package/src/rust/components/plugin_tab.rs +126 -112
- package/src/rust/components/settings_panel.rs +26 -20
- package/src/rust/components/status_bar.rs +0 -1
- package/src/rust/components/style_controls/number_string_format/digits_section.rs +22 -10
- package/src/rust/components/style_controls/number_string_format/misc_section.rs +6 -2
- package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -0
- package/src/rust/components/style_controls/number_string_format/types.rs +24 -0
- package/src/rust/components/style_controls/number_string_format.rs +37 -14
- package/src/rust/components/viewer/msg.rs +46 -7
- package/src/rust/components/viewer/panels.rs +11 -9
- package/src/rust/components/viewer/render.rs +8 -3
- package/src/rust/components/viewer/settings.rs +163 -23
- package/src/rust/components/viewer/snapshots.rs +46 -21
- package/src/rust/components/viewer/wiring.rs +14 -25
- package/src/rust/components/viewer.rs +12 -8
- package/src/rust/config/column_config_schema.rs +435 -45
- package/src/rust/config/css_scale.rs +882 -0
- package/src/rust/config/datetime_column_style.rs +4 -21
- package/src/rust/config/mod.rs +2 -0
- package/src/rust/config/number_string_format.rs +211 -18
- package/src/rust/config/options.rs +10 -0
- package/src/rust/config/viewer_config.rs +49 -55
- package/src/rust/config/workspace_config.rs +132 -5
- package/src/rust/custom_elements/viewer.rs +214 -155
- package/src/rust/custom_events.rs +14 -1
- package/src/rust/js/regular_layout.rs +3 -3
- package/src/rust/lib.rs +2 -0
- package/src/rust/presentation/column_locator.rs +19 -5
- package/src/rust/presentation.rs +209 -36
- package/src/rust/queries/column_locator.rs +74 -44
- package/src/rust/queries/get_viewer_config.rs +0 -3
- package/src/rust/queries/mod.rs +2 -0
- package/src/rust/queries/palette_set.rs +82 -0
- package/src/rust/queries/plugin_column_styles.rs +6 -2
- package/src/rust/renderer/dispatch.rs +50 -12
- package/src/rust/renderer/plugin_config.rs +362 -53
- package/src/rust/renderer.rs +15 -42
- package/src/rust/session/column_defaults_update.rs +15 -8
- package/src/rust/session/metadata.rs +5 -1
- package/src/rust/session/props.rs +1 -0
- package/src/rust/session.rs +9 -6
- package/src/rust/tasks/create_panel.rs +44 -57
- package/src/rust/tasks/edit_expression.rs +19 -23
- package/src/rust/tasks/edit_window.rs +8 -10
- package/src/rust/tasks/eject.rs +4 -1
- package/src/rust/tasks/pipeline.rs +2 -2
- package/src/rust/tasks/presize_panels.rs +44 -5
- package/src/rust/tasks/reset_all.rs +4 -4
- package/src/rust/tasks/restore_and_render.rs +17 -44
- package/src/rust/tasks/restore_panel.rs +11 -13
- package/src/rust/tasks/set_edit_mode.rs +3 -1
- package/src/rust/tasks/sync_update_panels.rs +11 -1
- package/src/rust/tasks/update_theme.rs +23 -18
- package/src/rust/utils/css_vars.rs +26 -0
- package/src/rust/utils/mod.rs +2 -0
- package/src/rust/utils/spawn.rs +1 -1
- package/src/rust/workspace.rs +435 -272
- package/src/svg/lock.svg +7 -0
- package/src/themes/blueprint.css +190 -0
- package/src/themes/botanical.css +14 -17
- package/src/themes/defaults.css +4 -110
- package/src/themes/dracula.css +19 -14
- package/src/themes/eggplant.css +189 -0
- package/src/themes/gruvbox-dark.css +23 -15
- package/src/themes/gruvbox.css +11 -1
- package/src/themes/icons.css +2 -2
- package/src/themes/intl/de.css +23 -1
- package/src/themes/intl/es.css +23 -1
- package/src/themes/intl/fr.css +23 -1
- package/src/themes/intl/ja.css +23 -1
- package/src/themes/intl/pt.css +23 -1
- package/src/themes/intl/zh.css +23 -1
- package/src/themes/intl.css +26 -4
- package/src/themes/ledger.css +195 -0
- package/src/themes/monokai.css +24 -14
- package/src/themes/nord.css +186 -0
- package/src/themes/phosphor.css +7 -14
- package/src/themes/pro-dark.css +12 -16
- package/src/themes/pro.css +118 -0
- package/src/themes/solarized-dark.css +9 -16
- package/src/themes/solarized.css +7 -0
- package/src/themes/themes.css +10 -5
- package/src/themes/vaporwave.css +22 -14
- package/src/themes/velvet.css +192 -0
- package/src/ts/column-format.ts +52 -2
- package/src/ts/perspective-viewer.ts +1 -0
- package/src/ts/plugin.ts +14 -0
- package/src/ts/ts-rs/PanelViewerConfig.ts +1 -1
- package/src/ts/ts-rs/SaveWorkspaceOptions.ts +11 -0
- package/src/ts/ts-rs/ViewerConfig.ts +1 -1
- package/src/ts/ts-rs/WorkspaceConfig.ts +8 -2
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +11 -3
- package/src/rust/components/form/color_range_selector.rs +0 -137
- package/src/svg/dropdown-selector-light.svg +0 -3
- /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline5.js +0 -0
|
@@ -42,6 +42,7 @@ use crate::tasks::{
|
|
|
42
42
|
delete_expr, delete_window, save_expr, save_window, update_expr, update_window,
|
|
43
43
|
};
|
|
44
44
|
use crate::utils::PtrEqRc;
|
|
45
|
+
use crate::workspace::Workspace;
|
|
45
46
|
|
|
46
47
|
#[derive(Clone, Derivative, Properties)]
|
|
47
48
|
#[derivative(Debug)]
|
|
@@ -91,12 +92,13 @@ pub struct ColumnSettingsPanelProps {
|
|
|
91
92
|
|
|
92
93
|
#[derivative(Debug = "ignore")]
|
|
93
94
|
pub session: Session,
|
|
95
|
+
|
|
96
|
+
#[derivative(Debug = "ignore")]
|
|
97
|
+
pub workspace: Workspace,
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
impl ColumnSettingsPanelProps {
|
|
97
|
-
|
|
98
|
-
/// invalidates the drafts that `initialize` rebuilds.
|
|
99
|
-
fn identity_eq(&self, other: &Self) -> bool {
|
|
100
|
+
impl PartialEq for ColumnSettingsPanelProps {
|
|
101
|
+
fn eq(&self, other: &Self) -> bool {
|
|
100
102
|
self.selected_column == other.selected_column
|
|
101
103
|
&& self.selected_tab == other.selected_tab
|
|
102
104
|
&& self.plugin_name == other.plugin_name
|
|
@@ -104,14 +106,46 @@ impl ColumnSettingsPanelProps {
|
|
|
104
106
|
&& self.view_config == other.view_config
|
|
105
107
|
&& self.column_stats == other.column_stats
|
|
106
108
|
&& self.selected_theme == other.selected_theme
|
|
109
|
+
&& self.auto_width == other.auto_width
|
|
110
|
+
&& self.is_pinned == other.is_pinned
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
#[derive(Clone, PartialEq)]
|
|
115
|
+
struct Initials {
|
|
116
|
+
column_name: String,
|
|
117
|
+
expr: Rc<String>,
|
|
118
|
+
header: Option<String>,
|
|
119
|
+
window: Option<WindowSpec>,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
impl Initials {
|
|
123
|
+
fn of(props: &ColumnSettingsPanelProps) -> Self {
|
|
124
|
+
let column_name = props
|
|
125
|
+
.metadata
|
|
126
|
+
.locator_name_or_default(&props.selected_column);
|
|
127
|
+
|
|
128
|
+
let expr = props
|
|
129
|
+
.metadata
|
|
130
|
+
.get_expression_by_alias(&column_name)
|
|
131
|
+
.or_else(|| props.view_config.expressions.get(&column_name).cloned())
|
|
132
|
+
.unwrap_or_default();
|
|
133
|
+
|
|
134
|
+
let expr = Rc::new(expr);
|
|
135
|
+
let header = (*expr != column_name).then_some(column_name.clone());
|
|
136
|
+
|
|
137
|
+
let window = props
|
|
138
|
+
.selected_column
|
|
139
|
+
.name()
|
|
140
|
+
.and_then(|name| props.view_config.windows.get(name))
|
|
141
|
+
.cloned();
|
|
142
|
+
|
|
143
|
+
Self {
|
|
144
|
+
column_name,
|
|
145
|
+
expr,
|
|
146
|
+
header,
|
|
147
|
+
window,
|
|
148
|
+
}
|
|
115
149
|
}
|
|
116
150
|
}
|
|
117
151
|
|
|
@@ -172,22 +206,23 @@ impl Component for ColumnSettingsPanel {
|
|
|
172
206
|
initial_window_value: None,
|
|
173
207
|
window_value: None,
|
|
174
208
|
tabs: vec![],
|
|
175
|
-
on_input:
|
|
176
|
-
on_save:
|
|
177
|
-
|
|
209
|
+
on_input: ctx.link().callback(ColumnSettingsPanelMsg::SetExprValue),
|
|
210
|
+
on_save: ctx
|
|
211
|
+
.link()
|
|
212
|
+
.callback(ColumnSettingsPanelMsg::OnSaveAttributes),
|
|
213
|
+
on_validate: ctx.link().callback(ColumnSettingsPanelMsg::SetExprValid),
|
|
178
214
|
};
|
|
179
215
|
|
|
180
|
-
this.
|
|
216
|
+
this.reset_to(ctx, Initials::of(ctx.props()));
|
|
181
217
|
this
|
|
182
218
|
}
|
|
183
219
|
|
|
184
220
|
fn changed(&mut self, ctx: &yew::prelude::Context<Self>, old_props: &Self::Properties) -> bool {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
self.initialize(ctx);
|
|
221
|
+
let next = Initials::of(ctx.props());
|
|
222
|
+
if ctx.props().selected_column != old_props.selected_column || next != self.initials() {
|
|
223
|
+
self.reset_to(ctx, next);
|
|
224
|
+
} else {
|
|
225
|
+
self.refresh_derived(ctx);
|
|
191
226
|
}
|
|
192
227
|
|
|
193
228
|
true
|
|
@@ -353,9 +388,9 @@ impl Component for ColumnSettingsPanel {
|
|
|
353
388
|
};
|
|
354
389
|
|
|
355
390
|
let header_props = props!(EditableHeaderProps {
|
|
391
|
+
value: self.header_value.clone(),
|
|
356
392
|
initial_value: self.initial_header_value.clone(),
|
|
357
393
|
placeholder: header_placeholder,
|
|
358
|
-
reset_count: self.reset_count,
|
|
359
394
|
editable: (ctx.props().selected_column.is_expr()
|
|
360
395
|
&& matches!(
|
|
361
396
|
ctx.props().selected_tab,
|
|
@@ -374,7 +409,6 @@ impl Component for ColumnSettingsPanel {
|
|
|
374
409
|
]
|
|
375
410
|
}),
|
|
376
411
|
metadata: ctx.props().metadata.clone(),
|
|
377
|
-
session: &ctx.props().session
|
|
378
412
|
});
|
|
379
413
|
|
|
380
414
|
let expr_editor = props!(ExpressionEditorProps {
|
|
@@ -382,6 +416,7 @@ impl Component for ColumnSettingsPanel {
|
|
|
382
416
|
on_save: self.on_save.clone(),
|
|
383
417
|
on_validate: self.on_validate.clone(),
|
|
384
418
|
alias: ctx.props().selected_column.name().cloned(),
|
|
419
|
+
initial_expr: self.initial_expr_value.clone(),
|
|
385
420
|
disabled: !ctx.props().selected_column.is_expr(),
|
|
386
421
|
reset_count: self.reset_count,
|
|
387
422
|
metadata: ctx.props().metadata.clone(),
|
|
@@ -457,6 +492,7 @@ impl Component for ColumnSettingsPanel {
|
|
|
457
492
|
presentation: ctx.props().presentation.clone(),
|
|
458
493
|
renderer: ctx.props().renderer.clone(),
|
|
459
494
|
session: ctx.props().session.clone(),
|
|
495
|
+
workspace: ctx.props().workspace.clone(),
|
|
460
496
|
};
|
|
461
497
|
|
|
462
498
|
let tab_children = self.tabs.iter().map(|tab| match tab {
|
|
@@ -506,38 +542,22 @@ impl ColumnSettingsPanel {
|
|
|
506
542
|
self.save_enabled = changed && valid;
|
|
507
543
|
}
|
|
508
544
|
|
|
509
|
-
fn
|
|
510
|
-
|
|
511
|
-
.
|
|
512
|
-
.
|
|
513
|
-
.
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
.metadata
|
|
518
|
-
.get_expression_by_alias(&column_name)
|
|
519
|
-
.unwrap_or_default();
|
|
520
|
-
|
|
521
|
-
let initial_expr_value = Rc::new(initial_expr_value);
|
|
522
|
-
let initial_header_value =
|
|
523
|
-
(*initial_expr_value != column_name).then_some(column_name.clone());
|
|
545
|
+
fn initials(&self) -> Initials {
|
|
546
|
+
Initials {
|
|
547
|
+
column_name: self.column_name.clone(),
|
|
548
|
+
expr: self.initial_expr_value.clone(),
|
|
549
|
+
header: self.initial_header_value.clone(),
|
|
550
|
+
window: self.initial_window_value.clone(),
|
|
551
|
+
}
|
|
552
|
+
}
|
|
524
553
|
|
|
525
|
-
|
|
554
|
+
fn refresh_derived(&mut self, ctx: &yew::prelude::Context<Self>) {
|
|
555
|
+
self.maybe_ty = ctx
|
|
526
556
|
.props()
|
|
527
557
|
.metadata
|
|
528
558
|
.locator_view_type(&ctx.props().selected_column);
|
|
529
559
|
|
|
530
|
-
|
|
531
|
-
// editable header owns naming in the UI), so drafts and saved specs
|
|
532
|
-
// compare directly.
|
|
533
|
-
let initial_window_value = ctx
|
|
534
|
-
.props()
|
|
535
|
-
.selected_column
|
|
536
|
-
.name()
|
|
537
|
-
.and_then(|name| ctx.props().view_config.windows.get(name))
|
|
538
|
-
.cloned();
|
|
539
|
-
|
|
540
|
-
let tabs = {
|
|
560
|
+
self.tabs = {
|
|
541
561
|
let mut tabs = vec![];
|
|
542
562
|
let is_new_expr = ctx.props().selected_column.is_new_expr();
|
|
543
563
|
let show_styles = !is_new_expr
|
|
@@ -571,28 +591,27 @@ impl ColumnSettingsPanel {
|
|
|
571
591
|
|
|
572
592
|
tabs
|
|
573
593
|
};
|
|
594
|
+
}
|
|
574
595
|
|
|
575
|
-
|
|
576
|
-
let
|
|
577
|
-
.link()
|
|
578
|
-
.callback(ColumnSettingsPanelMsg::OnSaveAttributes);
|
|
579
|
-
|
|
580
|
-
let on_validate = ctx.link().callback(ColumnSettingsPanelMsg::SetExprValid);
|
|
581
|
-
*self = Self {
|
|
596
|
+
fn reset_to(&mut self, ctx: &yew::prelude::Context<Self>, initials: Initials) {
|
|
597
|
+
let Initials {
|
|
582
598
|
column_name,
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
599
|
+
expr,
|
|
600
|
+
header,
|
|
601
|
+
window,
|
|
602
|
+
} = initials;
|
|
603
|
+
|
|
604
|
+
self.column_name = column_name;
|
|
605
|
+
self.expr_value = expr.clone();
|
|
606
|
+
self.initial_expr_value = expr;
|
|
607
|
+
self.header_value = header.clone();
|
|
608
|
+
self.initial_header_value = header;
|
|
609
|
+
self.window_value = window.clone();
|
|
610
|
+
self.initial_window_value = window;
|
|
611
|
+
self.header_valid = true;
|
|
612
|
+
self.save_enabled = false;
|
|
613
|
+
self.reset_enabled = false;
|
|
614
|
+
self.reset_count = self.reset_count.wrapping_add(1);
|
|
615
|
+
self.refresh_derived(ctx);
|
|
597
616
|
}
|
|
598
617
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
|
|
13
|
+
use wasm_bindgen::JsCast;
|
|
14
|
+
use web_sys::{Event, MouseEvent};
|
|
15
|
+
use yew::{Callback, Html, Properties, function_component, html, use_callback, use_mut_ref};
|
|
16
|
+
|
|
17
|
+
#[derive(Properties, PartialEq)]
|
|
18
|
+
pub struct ControlGroupProps {
|
|
19
|
+
pub group_key: String,
|
|
20
|
+
|
|
21
|
+
pub open: bool,
|
|
22
|
+
|
|
23
|
+
pub on_toggle: Callback<(String, bool)>,
|
|
24
|
+
|
|
25
|
+
pub children: Html,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[function_component]
|
|
29
|
+
pub fn ControlGroup(props: &ControlGroupProps) -> Html {
|
|
30
|
+
let ontoggle = use_callback(
|
|
31
|
+
(props.group_key.clone(), props.on_toggle.clone()),
|
|
32
|
+
|event: Event, (group_key, on_toggle)| {
|
|
33
|
+
if let Some(el) = event
|
|
34
|
+
.target()
|
|
35
|
+
.and_then(|x| x.dyn_into::<web_sys::Element>().ok())
|
|
36
|
+
{
|
|
37
|
+
on_toggle.emit((group_key.clone(), el.has_attribute("open")));
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
let onclick = use_callback((), |event: MouseEvent, _| {
|
|
43
|
+
if !event.shift_key() {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
event.prevent_default();
|
|
48
|
+
let Some(details) = event
|
|
49
|
+
.target()
|
|
50
|
+
.and_then(|x| x.dyn_into::<web_sys::Element>().ok())
|
|
51
|
+
.and_then(|x| x.closest("details.control-group").ok().flatten())
|
|
52
|
+
else {
|
|
53
|
+
return;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
let Some(scope) = details.closest(".tab-section").ok().flatten() else {
|
|
57
|
+
return;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
let expand = !details.has_attribute("open");
|
|
61
|
+
let Ok(groups) = scope.query_selector_all("details.control-group") else {
|
|
62
|
+
return;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for i in 0..groups.length() {
|
|
66
|
+
let Some(el) = groups
|
|
67
|
+
.item(i)
|
|
68
|
+
.and_then(|x| x.dyn_into::<web_sys::Element>().ok())
|
|
69
|
+
else {
|
|
70
|
+
continue;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if expand {
|
|
74
|
+
let _ = el.set_attribute("open", "");
|
|
75
|
+
} else {
|
|
76
|
+
let _ = el.remove_attribute("open");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
let open = *use_mut_ref(|| props.open).borrow();
|
|
82
|
+
html! {
|
|
83
|
+
<details class="control-group" {open} {ontoggle}>
|
|
84
|
+
<summary {onclick}>
|
|
85
|
+
<span class="control-group-chevron shift-alt-icon" />
|
|
86
|
+
<label id={format!("{}-group-label", props.group_key)} />
|
|
87
|
+
</summary>
|
|
88
|
+
{ props.children.clone() }
|
|
89
|
+
</details>
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -230,9 +230,15 @@ where
|
|
|
230
230
|
<label>
|
|
231
231
|
{ ctx.props().label.as_ref().map(|x| x.to_string()).unwrap_or_default() }
|
|
232
232
|
</label>
|
|
233
|
-
<div class={wrapper_class} data-value={value}>
|
|
233
|
+
<div class={wrapper_class} data-value={value}>
|
|
234
|
+
{ select }
|
|
235
|
+
<span class="select-arrow" />
|
|
236
|
+
</div>
|
|
234
237
|
} else {
|
|
235
|
-
<div class={wrapper_class} data-value={value}>
|
|
238
|
+
<div class={wrapper_class} data-value={value}>
|
|
239
|
+
{ select }
|
|
240
|
+
<span class="select-arrow" />
|
|
241
|
+
</div>
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
244
|
}
|
|
@@ -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
|
|
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.
|
|
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.
|
|
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={
|
|
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
|
|
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
|
-
*
|
|
111
|
+
*format.time_zone_mut() = val;
|
|
104
112
|
} else {
|
|
105
|
-
*
|
|
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.
|
|
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.
|
|
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={
|
|
161
|
+
current_value={format.time_zone().as_ref().unwrap_or(&*USER_TIMEZONE).clone()}
|
|
135
162
|
/>
|
|
136
163
|
}
|
|
137
|
-
if let DatetimeFormatType::Simple(config) = &
|
|
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) = &
|
|
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={
|
|
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() {
|