@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.
Files changed (179) 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.d.ts +1 -0
  31. package/dist/esm/perspective-viewer.inline.js +9 -9
  32. package/dist/esm/perspective-viewer.inline.js.map +3 -3
  33. package/dist/esm/perspective-viewer.js +8 -8
  34. package/dist/esm/perspective-viewer.js.map +3 -3
  35. package/dist/esm/plugin.d.ts +10 -0
  36. package/dist/esm/ts-rs/PanelViewerConfig.d.ts +1 -1
  37. package/dist/esm/ts-rs/SaveWorkspaceOptions.d.ts +10 -0
  38. package/dist/esm/ts-rs/ViewerConfig.d.ts +1 -1
  39. package/dist/esm/ts-rs/WorkspaceConfig.d.ts +9 -1
  40. package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +13 -3
  41. package/dist/wasm/perspective-viewer.d.ts +43 -36
  42. package/dist/wasm/perspective-viewer.js +198 -136
  43. package/dist/wasm/perspective-viewer.wasm +0 -0
  44. package/dist/wasm/perspective-viewer.wasm.d.ts +19 -17
  45. package/package.json +1 -1
  46. package/src/css/column-settings-panel.css +28 -5
  47. package/src/css/column-style.css +291 -31
  48. package/src/css/containers/tabs.css +13 -3
  49. package/src/css/dom/select.css +21 -9
  50. package/src/css/form/code-editor.css +4 -4
  51. package/src/css/plugin-selector.css +1 -0
  52. package/src/css/plugin-settings-panel.css +72 -0
  53. package/src/css/viewer.css +0 -5
  54. package/src/rust/agent/tools.rs +53 -19
  55. package/src/rust/components/column_selector/active_column.rs +2 -2
  56. package/src/rust/components/column_selector/add_expression_button.rs +3 -3
  57. package/src/rust/components/column_selector/aggregate_selector.rs +2 -3
  58. package/src/rust/components/column_selector/config_selector.rs +8 -0
  59. package/src/rust/components/column_selector/expr_edit_button.rs +4 -10
  60. package/src/rust/components/column_selector/inactive_column.rs +2 -2
  61. package/src/rust/components/column_selector.rs +48 -4
  62. package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +293 -126
  63. package/src/rust/components/column_settings_sidebar/style_tab.rs +330 -234
  64. package/src/rust/components/column_settings_sidebar.rs +88 -69
  65. package/src/rust/components/containers/control_group.rs +91 -0
  66. package/src/rust/components/containers/mod.rs +1 -0
  67. package/src/rust/components/containers/select.rs +8 -2
  68. package/src/rust/components/datetime_column_style/simple.rs +15 -4
  69. package/src/rust/components/datetime_column_style.rs +50 -10
  70. package/src/rust/components/editable_header.rs +85 -144
  71. package/src/rust/components/expression_editor.rs +9 -16
  72. package/src/rust/components/form/code_editor.rs +16 -6
  73. package/src/rust/components/form/debug.rs +1 -0
  74. package/src/rust/components/form/mod.rs +3 -1
  75. package/src/rust/components/form/multi_stop_gradient_selector.rs +476 -0
  76. package/src/rust/components/form/named_value_picker.rs +86 -0
  77. package/src/rust/components/form/palette_selector.rs +440 -0
  78. package/src/rust/components/main_panel/msg.rs +2 -2
  79. package/src/rust/components/main_panel/reconcile.rs +4 -4
  80. package/src/rust/components/plugin_tab.rs +126 -112
  81. package/src/rust/components/settings_panel.rs +26 -20
  82. package/src/rust/components/status_bar.rs +0 -1
  83. package/src/rust/components/style_controls/number_string_format/digits_section.rs +22 -10
  84. package/src/rust/components/style_controls/number_string_format/misc_section.rs +6 -2
  85. package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -0
  86. package/src/rust/components/style_controls/number_string_format/types.rs +24 -0
  87. package/src/rust/components/style_controls/number_string_format.rs +37 -14
  88. package/src/rust/components/viewer/msg.rs +46 -7
  89. package/src/rust/components/viewer/panels.rs +11 -9
  90. package/src/rust/components/viewer/render.rs +8 -3
  91. package/src/rust/components/viewer/settings.rs +163 -23
  92. package/src/rust/components/viewer/snapshots.rs +46 -21
  93. package/src/rust/components/viewer/wiring.rs +14 -25
  94. package/src/rust/components/viewer.rs +12 -8
  95. package/src/rust/config/column_config_schema.rs +435 -45
  96. package/src/rust/config/css_scale.rs +882 -0
  97. package/src/rust/config/datetime_column_style.rs +4 -21
  98. package/src/rust/config/mod.rs +2 -0
  99. package/src/rust/config/number_string_format.rs +211 -18
  100. package/src/rust/config/options.rs +10 -0
  101. package/src/rust/config/viewer_config.rs +49 -55
  102. package/src/rust/config/workspace_config.rs +132 -5
  103. package/src/rust/custom_elements/viewer.rs +214 -155
  104. package/src/rust/custom_events.rs +14 -1
  105. package/src/rust/js/regular_layout.rs +3 -3
  106. package/src/rust/lib.rs +2 -0
  107. package/src/rust/presentation/column_locator.rs +19 -5
  108. package/src/rust/presentation.rs +209 -36
  109. package/src/rust/queries/column_locator.rs +74 -44
  110. package/src/rust/queries/get_viewer_config.rs +0 -3
  111. package/src/rust/queries/mod.rs +2 -0
  112. package/src/rust/queries/palette_set.rs +82 -0
  113. package/src/rust/queries/plugin_column_styles.rs +6 -2
  114. package/src/rust/renderer/dispatch.rs +50 -12
  115. package/src/rust/renderer/plugin_config.rs +362 -53
  116. package/src/rust/renderer.rs +15 -42
  117. package/src/rust/session/column_defaults_update.rs +15 -8
  118. package/src/rust/session/metadata.rs +5 -1
  119. package/src/rust/session/props.rs +1 -0
  120. package/src/rust/session.rs +9 -6
  121. package/src/rust/tasks/create_panel.rs +44 -57
  122. package/src/rust/tasks/edit_expression.rs +19 -23
  123. package/src/rust/tasks/edit_window.rs +8 -10
  124. package/src/rust/tasks/eject.rs +4 -1
  125. package/src/rust/tasks/pipeline.rs +2 -2
  126. package/src/rust/tasks/presize_panels.rs +44 -5
  127. package/src/rust/tasks/reset_all.rs +4 -4
  128. package/src/rust/tasks/restore_and_render.rs +17 -44
  129. package/src/rust/tasks/restore_panel.rs +11 -13
  130. package/src/rust/tasks/set_edit_mode.rs +3 -1
  131. package/src/rust/tasks/sync_update_panels.rs +11 -1
  132. package/src/rust/tasks/update_theme.rs +23 -18
  133. package/src/rust/utils/css_vars.rs +26 -0
  134. package/src/rust/utils/mod.rs +2 -0
  135. package/src/rust/utils/spawn.rs +1 -1
  136. package/src/rust/workspace.rs +435 -272
  137. package/src/svg/lock.svg +7 -0
  138. package/src/themes/blueprint.css +190 -0
  139. package/src/themes/botanical.css +14 -17
  140. package/src/themes/defaults.css +4 -110
  141. package/src/themes/dracula.css +19 -14
  142. package/src/themes/eggplant.css +189 -0
  143. package/src/themes/gruvbox-dark.css +23 -15
  144. package/src/themes/gruvbox.css +11 -1
  145. package/src/themes/icons.css +2 -2
  146. package/src/themes/intl/de.css +23 -1
  147. package/src/themes/intl/es.css +23 -1
  148. package/src/themes/intl/fr.css +23 -1
  149. package/src/themes/intl/ja.css +23 -1
  150. package/src/themes/intl/pt.css +23 -1
  151. package/src/themes/intl/zh.css +23 -1
  152. package/src/themes/intl.css +26 -4
  153. package/src/themes/ledger.css +195 -0
  154. package/src/themes/monokai.css +24 -14
  155. package/src/themes/nord.css +186 -0
  156. package/src/themes/phosphor.css +7 -14
  157. package/src/themes/pro-dark.css +12 -16
  158. package/src/themes/pro.css +118 -0
  159. package/src/themes/solarized-dark.css +9 -16
  160. package/src/themes/solarized.css +7 -0
  161. package/src/themes/themes.css +10 -5
  162. package/src/themes/vaporwave.css +22 -14
  163. package/src/themes/velvet.css +192 -0
  164. package/src/ts/column-format.ts +52 -2
  165. package/src/ts/perspective-viewer.ts +1 -0
  166. package/src/ts/plugin.ts +14 -0
  167. package/src/ts/ts-rs/PanelViewerConfig.ts +1 -1
  168. package/src/ts/ts-rs/SaveWorkspaceOptions.ts +11 -0
  169. package/src/ts/ts-rs/ViewerConfig.ts +1 -1
  170. package/src/ts/ts-rs/WorkspaceConfig.ts +8 -2
  171. package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +11 -3
  172. package/src/rust/components/form/color_range_selector.rs +0 -137
  173. package/src/svg/dropdown-selector-light.svg +0 -3
  174. /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline0.js +0 -0
  175. /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline1.js +0 -0
  176. /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline2.js +0 -0
  177. /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline3.js +0 -0
  178. /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline4.js +0 -0
  179. /package/dist/wasm/snippets/{perspective-viewer-02e461f3d7062b26 → perspective-viewer-87bd21b215d0631a}/inline5.js +0 -0
@@ -125,11 +125,6 @@
125
125
  0 12.5px 0 -11.5px var(--psp-inactive--border-color);
126
126
  }
127
127
 
128
- :host input[type="number"]::-webkit-inner-spin-button {
129
- transform: scale(1.5) translateX(-5px);
130
- filter: var(--psp-input--filter);
131
- }
132
-
133
128
  :host .sidebar_close_button {
134
129
  position: absolute;
135
130
  top: 0;
@@ -630,25 +630,56 @@ fn control_schema_entries(spec: &ControlSpec) -> Vec<(String, Value)> {
630
630
  },
631
631
  ControlSpec::Color { key, default } => vec![(
632
632
  key.clone(),
633
- json!({ "type": "string", "format": "color", "default": default }),
633
+ json!({
634
+ "type": "string",
635
+ "description": "A CSS color (`#rrggbb`, `rgb()`), or a host-defined named color `var(--psp-user--color-<name>)`",
636
+ "default": default,
637
+ }),
634
638
  )],
635
- ControlSpec::ColorRange {
636
- key_pos,
637
- key_neg,
638
- default_pos,
639
- default_neg,
640
- ..
641
- } => vec![
642
- (
643
- key_pos.clone(),
644
- json!({ "type": "string", "format": "color", "default": default_pos }),
645
- ),
646
- (
647
- key_neg.clone(),
648
- json!({ "type": "string", "format": "color", "default": default_neg }),
649
- ),
650
- ],
651
- ControlSpec::DatetimeFormat => vec![(
639
+ ControlSpec::Palette { key, default, max } => {
640
+ let mut description = "Ordered discrete color palette, cycled over the column's \
641
+ categories/series: a CSS `linear-gradient(to right, #rrggbb, \
642
+ #rrggbb, …)` of N colors WITHOUT positions, or a host-defined \
643
+ named palette `var(--psp-user--palette-<name>)`"
644
+ .to_owned();
645
+ if let Some(max) = max {
646
+ description.push_str(&format!(" (at most {max} colors)"));
647
+ }
648
+
649
+ vec![(
650
+ key.clone(),
651
+ json!({
652
+ "type": "string",
653
+ "description": description,
654
+ "default": default,
655
+ }),
656
+ )]
657
+ },
658
+ ControlSpec::GradientStops {
659
+ key,
660
+ default,
661
+ discrete,
662
+ } => {
663
+ let mut description = "Multi-stop color gradient: a CSS `linear-gradient(to right, \
664
+ #rrggbb P%, …)` with positioned stops (direction normalized to \
665
+ `to right`; stops[0] maps to the most negative value), or a \
666
+ host-defined named gradient `var(--psp-user--gradient-<name>)`"
667
+ .to_owned();
668
+
669
+ if *discrete {
670
+ description.push_str(" — exactly 2 stops (the negative and positive colors)");
671
+ }
672
+
673
+ vec![(
674
+ key.clone(),
675
+ json!({
676
+ "type": "string",
677
+ "description": description,
678
+ "default": default,
679
+ }),
680
+ )]
681
+ },
682
+ ControlSpec::DatetimeFormat { .. } => vec![(
652
683
  "date_format".to_owned(),
653
684
  json!({ "description": "Datetime display format: a style preset or custom format fields" }),
654
685
  )],
@@ -670,7 +701,7 @@ fn control_schema_entries(spec: &ControlSpec) -> Vec<(String, Value)> {
670
701
  "symbols".to_owned(),
671
702
  json!({ "type": "object", "description": "Map of column values to symbol names" }),
672
703
  )],
673
- ControlSpec::NumberFormat => vec![(
704
+ ControlSpec::NumberFormat { .. } => vec![(
674
705
  "number_format".to_owned(),
675
706
  json!({ "type": "object", "description": "Intl.NumberFormat-style options" }),
676
707
  )],
@@ -678,6 +709,9 @@ fn control_schema_entries(spec: &ControlSpec) -> Vec<(String, Value)> {
678
709
  "aggregate_depth".to_owned(),
679
710
  json!({ "type": "integer", "description": "Group-by rollup depth override" }),
680
711
  )],
712
+ ControlSpec::Group { fields, .. } => {
713
+ fields.iter().flat_map(control_schema_entries).collect()
714
+ },
681
715
  }
682
716
  }
683
717
 
@@ -23,7 +23,7 @@ use super::expr_edit_button::*;
23
23
  use crate::components::column_dropdown::ColumnDropDownElement;
24
24
  use crate::components::column_selector::{EmptyColumn, InvalidColumn};
25
25
  use crate::config::ColumnSelectMode;
26
- use crate::presentation::{ColumnLocator, Presentation};
26
+ use crate::presentation::{ColumnSettingsTarget, Presentation};
27
27
  use crate::queries::*;
28
28
  use crate::renderer::*;
29
29
  use crate::session::*;
@@ -51,7 +51,7 @@ pub struct ActiveColumnProps {
51
51
  pub onselect: Callback<()>,
52
52
 
53
53
  /// Fires when this component's expression/config button is clicked.
54
- pub on_open_expr_panel: Callback<ColumnLocator>,
54
+ pub on_open_expr_panel: Callback<ColumnSettingsTarget>,
55
55
 
56
56
  /// Is this column in a grouped context (does the aggregate selector
57
57
  /// need to be visible)?
@@ -12,12 +12,12 @@
12
12
 
13
13
  use yew::prelude::*;
14
14
 
15
- use super::ColumnLocator;
15
+ use super::{ColumnLocator, ColumnSettingsTarget};
16
16
 
17
17
  #[derive(Clone, PartialEq, Properties)]
18
18
  pub struct AddExpressionButtonProps {
19
19
  // Fires when this button is clicked.
20
- pub on_open_expr_panel: Callback<ColumnLocator>,
20
+ pub on_open_expr_panel: Callback<ColumnSettingsTarget>,
21
21
 
22
22
  /// The column this butotn will open configuration for.
23
23
  pub selected_column: Option<ColumnLocator>,
@@ -47,7 +47,7 @@ pub fn AddExpressionButton(p: &AddExpressionButtonProps) -> Html {
47
47
 
48
48
  let onmousedown = p
49
49
  .on_open_expr_panel
50
- .reform(|_| ColumnLocator::NewExpression);
50
+ .reform(|_| ColumnSettingsTarget::NewExpression);
51
51
 
52
52
  let class = if *is_mouseover || matches!(p.selected_column, Some(ColumnLocator::NewExpression))
53
53
  {
@@ -10,9 +10,9 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- use std::collections::HashSet;
14
13
  use std::rc::Rc;
15
14
 
15
+ use itertools::Itertools;
16
16
  use perspective_client::config::*;
17
17
  use yew::prelude::*;
18
18
 
@@ -163,8 +163,7 @@ impl AggregateSelector {
163
163
  Aggregate::MultiAggregate(x, _) => Some(x),
164
164
  _ => None,
165
165
  })
166
- .collect::<HashSet<_>>()
167
- .into_iter()
166
+ .unique()
168
167
  .map(|x| {
169
168
  SelectItem::OptGroup(
170
169
  x.clone().into(),
@@ -279,6 +279,14 @@ impl Component for ConfigSelector {
279
279
  ctx.props().metadata.get_features().unwrap(),
280
280
  );
281
281
 
282
+ super::close_column_settings_if_displaced(
283
+ &ctx.props().presentation,
284
+ &ctx.props().renderer,
285
+ &ctx.props().metadata,
286
+ &ctx.props().view_config,
287
+ &update,
288
+ );
289
+
282
290
  {
283
291
  let session = ctx.props().session.clone();
284
292
  let renderer = ctx.props().renderer.clone();
@@ -12,7 +12,7 @@
12
12
 
13
13
  use yew::prelude::*;
14
14
 
15
- use super::ColumnLocator;
15
+ use super::ColumnSettingsTarget;
16
16
 
17
17
  #[derive(PartialEq, Clone, Properties)]
18
18
  pub struct ExprEditButtonProps {
@@ -27,7 +27,7 @@ pub struct ExprEditButtonProps {
27
27
  pub is_window: bool,
28
28
 
29
29
  /// Fires when the config/expresison button is clicked.
30
- pub on_open_expr_panel: Callback<ColumnLocator>,
30
+ pub on_open_expr_panel: Callback<ColumnSettingsTarget>,
31
31
 
32
32
  /// Is the expression/config panel open?
33
33
  pub is_editing: bool,
@@ -42,14 +42,8 @@ pub struct ExprEditButtonProps {
42
42
  #[function_component]
43
43
  pub fn ExprEditButton(p: &ExprEditButtonProps) -> Html {
44
44
  let onmousedown = yew::use_callback(p.clone(), |_, p| {
45
- let name = if p.is_window {
46
- ColumnLocator::Window(p.name.clone())
47
- } else if p.is_expression {
48
- ColumnLocator::Expression(p.name.clone())
49
- } else {
50
- ColumnLocator::Table(p.name.clone())
51
- };
52
- p.on_open_expr_panel.emit(name)
45
+ p.on_open_expr_panel
46
+ .emit(ColumnSettingsTarget::Column(p.name.clone()))
53
47
  });
54
48
 
55
49
  let class = if p.is_disabled {
@@ -18,7 +18,7 @@ use yew::prelude::*;
18
18
  use super::expr_edit_button::*;
19
19
  use crate::components::type_icon::TypeIcon;
20
20
  use crate::config::ColumnSelectMode;
21
- use crate::presentation::{ColumnLocator, Presentation};
21
+ use crate::presentation::{ColumnSettingsTarget, Presentation};
22
22
  use crate::renderer::*;
23
23
  use crate::session::*;
24
24
  use crate::tasks::apply_and_render;
@@ -61,7 +61,7 @@ pub struct InactiveColumnProps {
61
61
  pub onselect: Callback<()>,
62
62
 
63
63
  /// Fires when this column's expression/config button is clicked.
64
- pub on_open_expr_panel: Callback<ColumnLocator>,
64
+ pub on_open_expr_panel: Callback<ColumnSettingsTarget>,
65
65
 
66
66
  // State
67
67
  pub presentation: Presentation,
@@ -29,7 +29,7 @@ use std::rc::Rc;
29
29
  pub use column_selector_column_row::*;
30
30
  pub use empty_column::*;
31
31
  pub use invalid_column::*;
32
- use perspective_client::config::ViewConfig;
32
+ use perspective_client::config::{ViewConfig, ViewConfigUpdate};
33
33
  pub use pivot_column::*;
34
34
  use web_sys::*;
35
35
  use yew::prelude::*;
@@ -43,8 +43,10 @@ use super::containers::split_panel::{Orientation, SplitPanel};
43
43
  use crate::components::column_dropdown::{ColumnDropDownElement, ColumnDropDownPortal};
44
44
  use crate::components::containers::scroll_panel_item::ScrollPanelItem;
45
45
  use crate::config::PluginStaticConfig;
46
- use crate::presentation::{ColumnLocator, DragDropContainer, Presentation};
47
- use crate::queries::{ActiveColumnState, ActiveColumnStateData, ColumnsIteratorSet};
46
+ use crate::presentation::{ColumnLocator, ColumnSettingsTarget, DragDropContainer, Presentation};
47
+ use crate::queries::{
48
+ ActiveColumnState, ActiveColumnStateData, ColumnsIteratorSet, get_current_column_locator,
49
+ };
48
50
  use crate::renderer::*;
49
51
  use crate::session::drag_drop_update::*;
50
52
  use crate::session::*;
@@ -54,7 +56,7 @@ use crate::utils::*;
54
56
  #[derive(Properties)]
55
57
  pub struct ColumnSelectorProps {
56
58
  /// Fires when the expression/config column is open.
57
- pub on_open_expr_panel: Callback<ColumnLocator>,
59
+ pub on_open_expr_panel: Callback<ColumnSettingsTarget>,
58
60
 
59
61
  /// This is passed to the add_expression_button for styling.
60
62
  pub selected_column: Option<ColumnLocator>,
@@ -137,6 +139,32 @@ pub struct ColumnSelector {
137
139
  on_reset: Rc<PubSub<()>>,
138
140
  }
139
141
 
142
+ fn close_column_settings_if_displaced(
143
+ presentation: &Presentation,
144
+ renderer: &Renderer,
145
+ metadata: &SessionMetadata,
146
+ view_config: &ViewConfig,
147
+ update: &ViewConfigUpdate,
148
+ ) {
149
+ let Some(columns) = &update.columns else {
150
+ return;
151
+ };
152
+
153
+ let ocs = presentation.get_open_column_settings();
154
+ if get_current_column_locator(&ocs, renderer, view_config, metadata).is_none() {
155
+ return;
156
+ }
157
+
158
+ let next_config = ViewConfig {
159
+ columns: columns.clone(),
160
+ ..view_config.clone()
161
+ };
162
+
163
+ if get_current_column_locator(&ocs, renderer, &next_config, metadata).is_none() {
164
+ presentation.set_open_column_settings(None);
165
+ }
166
+ }
167
+
140
168
  impl Component for ColumnSelector {
141
169
  type Message = ColumnSelectorMsg;
142
170
  type Properties = ColumnSelectorProps;
@@ -224,6 +252,14 @@ impl Component for ColumnSelector {
224
252
  ctx.props().metadata.get_features().unwrap(),
225
253
  );
226
254
 
255
+ close_column_settings_if_displaced(
256
+ &ctx.props().presentation,
257
+ &ctx.props().renderer,
258
+ &ctx.props().metadata,
259
+ &ctx.props().view_config,
260
+ &update,
261
+ );
262
+
227
263
  let session = ctx.props().session.clone();
228
264
  let renderer = ctx.props().renderer.clone();
229
265
  if let Ok(task) = apply_and_render(&session, &renderer, update) {
@@ -249,6 +285,14 @@ impl Component for ColumnSelector {
249
285
  ctx.props().metadata.get_features().unwrap(),
250
286
  );
251
287
 
288
+ close_column_settings_if_displaced(
289
+ &ctx.props().presentation,
290
+ &ctx.props().renderer,
291
+ &ctx.props().metadata,
292
+ &ctx.props().view_config,
293
+ &update,
294
+ );
295
+
252
296
  let session = ctx.props().session.clone();
253
297
  let renderer = ctx.props().renderer.clone();
254
298
  if let Ok(task) = apply_and_render(&session, &renderer, update) {