@perspective-dev/viewer 4.0.0 → 4.1.0

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 (184) hide show
  1. package/dist/cdn/perspective-viewer.js +2 -2
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/dracula.css +1 -1
  4. package/dist/css/gruvbox-dark.css +1 -1
  5. package/dist/css/gruvbox.css +1 -1
  6. package/dist/css/icons.css +1 -1
  7. package/dist/css/monokai.css +1 -1
  8. package/dist/css/pro-dark.css +1 -1
  9. package/dist/css/pro.css +1 -1
  10. package/dist/css/solarized-dark.css +1 -1
  11. package/dist/css/solarized.css +1 -1
  12. package/dist/css/themes.css +1 -1
  13. package/dist/css/vaporwave.css +1 -1
  14. package/dist/esm/extensions.d.ts +23 -2
  15. package/dist/esm/perspective-viewer.d.ts +2 -7
  16. package/dist/esm/perspective-viewer.inline.js +2 -2
  17. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  18. package/dist/esm/perspective-viewer.js +2 -2
  19. package/dist/esm/perspective-viewer.js.map +4 -4
  20. package/dist/esm/plugin.d.ts +1 -1
  21. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +1 -0
  22. package/dist/wasm/perspective-viewer.d.ts +218 -46
  23. package/dist/wasm/perspective-viewer.js +1251 -762
  24. package/dist/wasm/perspective-viewer.wasm +0 -0
  25. package/dist/wasm/perspective-viewer.wasm.d.ts +38 -19
  26. package/package.json +1 -1
  27. package/src/less/containers/scroll-panel.less +0 -1
  28. package/src/less/plugin-selector.less +15 -5
  29. package/src/less/status-bar.less +75 -27
  30. package/src/less/viewer.less +140 -58
  31. package/src/rust/components/column_dropdown.rs +21 -21
  32. package/src/rust/components/column_selector/active_column.rs +131 -120
  33. package/src/rust/components/column_selector/add_expression_button.rs +5 -0
  34. package/src/rust/components/column_selector/aggregate_selector.rs +8 -4
  35. package/src/rust/components/column_selector/config_selector.rs +170 -161
  36. package/src/rust/components/column_selector/empty_column.rs +16 -11
  37. package/src/rust/components/column_selector/{expression_toolbar.rs → expr_edit_button.rs} +7 -0
  38. package/src/rust/components/column_selector/filter_column.rs +195 -194
  39. package/src/rust/components/column_selector/inactive_column.rs +82 -67
  40. package/src/rust/components/column_selector/pivot_column.rs +16 -11
  41. package/src/rust/components/column_selector/sort_column.rs +9 -7
  42. package/src/rust/components/column_selector.rs +42 -37
  43. package/src/rust/components/column_settings_sidebar/save_settings.rs +3 -1
  44. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +58 -0
  45. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +6 -6
  46. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +2 -94
  47. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +111 -0
  48. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +3 -3
  49. package/src/rust/components/column_settings_sidebar/style_tab.rs +23 -83
  50. package/src/rust/components/{column_settings_sidebar/sidebar.rs → column_settings_sidebar.rs} +198 -171
  51. package/src/rust/components/containers/dragdrop_list.rs +20 -20
  52. package/src/rust/components/containers/dropdown_menu.rs +4 -6
  53. package/src/rust/components/containers/mod.rs +1 -4
  54. package/src/rust/components/containers/scroll_panel.rs +80 -80
  55. package/src/rust/components/containers/scroll_panel_item.rs +36 -36
  56. package/src/rust/components/containers/select.rs +46 -44
  57. package/src/rust/components/containers/sidebar.rs +3 -19
  58. package/src/rust/components/{column_settings_sidebar/style_tab/symbol/symbol_config.rs → containers/sidebar_close_button.rs} +15 -9
  59. package/src/rust/components/containers/split_panel.rs +212 -200
  60. package/src/rust/components/containers/tab_list.rs +11 -11
  61. package/src/rust/components/copy_dropdown.rs +22 -25
  62. package/src/rust/components/datetime_column_style/custom.rs +19 -19
  63. package/src/rust/components/datetime_column_style/simple.rs +13 -14
  64. package/src/rust/components/datetime_column_style.rs +75 -76
  65. package/src/rust/components/editable_header.rs +18 -14
  66. package/src/rust/components/empty_row.rs +5 -5
  67. package/src/rust/components/export_dropdown.rs +42 -42
  68. package/src/rust/components/expression_editor.rs +25 -19
  69. package/src/rust/components/filter_dropdown.rs +22 -22
  70. package/src/rust/components/font_loader.rs +11 -9
  71. package/src/rust/components/form/code_editor.rs +106 -105
  72. package/src/rust/components/form/color_range_selector.rs +14 -12
  73. package/src/rust/components/form/color_selector.rs +3 -1
  74. package/src/rust/components/form/debug.rs +95 -94
  75. package/src/rust/components/form/highlight.rs +5 -3
  76. package/src/rust/components/form/mod.rs +3 -2
  77. package/src/rust/components/form/optional_field.rs +2 -2
  78. package/src/rust/components/form/{select_field.rs → select_enum_field.rs} +1 -46
  79. package/src/rust/components/form/select_value_field.rs +64 -0
  80. package/src/rust/components/function_dropdown.rs +21 -21
  81. package/src/rust/components/main_panel.rs +219 -0
  82. package/src/rust/components/mod.rs +6 -6
  83. package/src/rust/components/modal.rs +42 -42
  84. package/src/rust/components/number_column_style.rs +34 -88
  85. package/src/rust/components/plugin_selector.rs +22 -25
  86. package/src/rust/components/render_warning.rs +9 -6
  87. package/src/rust/components/settings_panel.rs +82 -0
  88. package/src/rust/components/status_bar.rs +250 -146
  89. package/src/rust/components/status_bar_counter.rs +26 -119
  90. package/src/rust/components/status_indicator.rs +95 -79
  91. package/src/rust/components/string_column_style.rs +45 -45
  92. package/src/rust/components/style/style_provider.rs +1 -15
  93. package/src/rust/components/style_controls/number_string_format/digits_section.rs +1 -1
  94. package/src/rust/components/style_controls/number_string_format/misc_section.rs +1 -1
  95. package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -1
  96. package/src/rust/components/style_controls/number_string_format.rs +45 -46
  97. package/src/rust/components/type_icon.rs +14 -11
  98. package/src/rust/components/viewer.rs +241 -384
  99. package/src/rust/config/columns_config.rs +2 -2
  100. package/src/rust/config/datetime_column_style.rs +1 -6
  101. package/src/rust/config/mod.rs +1 -0
  102. package/src/rust/config/number_column_style.rs +0 -6
  103. package/src/rust/config/number_string_format.rs +27 -4
  104. package/src/rust/config/viewer_config.rs +27 -167
  105. package/src/rust/custom_elements/copy_dropdown.rs +14 -6
  106. package/src/rust/custom_elements/export_dropdown.rs +15 -7
  107. package/src/rust/custom_elements/filter_dropdown.rs +4 -4
  108. package/src/rust/custom_elements/mod.rs +3 -0
  109. package/src/rust/custom_elements/viewer.rs +353 -161
  110. package/src/rust/custom_events.rs +55 -32
  111. package/src/rust/dragdrop.rs +4 -24
  112. package/src/rust/exprtk/cursor.rs +10 -1
  113. package/src/rust/exprtk/mod.rs +2 -0
  114. package/src/rust/exprtk/tokenize.rs +20 -3
  115. package/src/rust/js/clipboard.rs +2 -2
  116. package/src/rust/js/mimetype.rs +2 -7
  117. package/src/rust/js/mod.rs +0 -1
  118. package/src/rust/js/plugin.rs +7 -0
  119. package/src/rust/lib.rs +18 -5
  120. package/src/rust/model/column_locator.rs +82 -0
  121. package/src/rust/model/columns_iter_set.rs +1 -0
  122. package/src/rust/model/copy_export.rs +50 -14
  123. package/src/rust/model/edit_expression.rs +2 -5
  124. package/src/rust/model/eject.rs +41 -0
  125. package/src/rust/model/export_app.rs +3 -2
  126. package/src/rust/model/get_viewer_config.rs +4 -28
  127. package/src/rust/model/intersection_observer.rs +20 -8
  128. package/src/rust/model/mod.rs +11 -4
  129. package/src/rust/model/plugin_column_styles.rs +0 -31
  130. package/src/rust/model/reset_all.rs +38 -0
  131. package/src/rust/model/resize_observer.rs +34 -7
  132. package/src/rust/model/restore_and_render.rs +12 -7
  133. package/src/rust/{utils/scope.rs → model/send_plugin_config.rs} +32 -35
  134. package/src/rust/model/structural.rs +194 -23
  135. package/src/rust/model/update_and_render.rs +14 -4
  136. package/src/rust/{model/create_col.rs → presentation/column_locator.rs} +73 -42
  137. package/src/rust/{utils/wasm_abi.rs → presentation/sheets.rs} +54 -40
  138. package/src/rust/presentation.rs +60 -119
  139. package/src/rust/renderer/activate.rs +20 -5
  140. package/src/rust/renderer/limits.rs +0 -149
  141. package/src/rust/renderer/render_timer.rs +1 -1
  142. package/src/rust/renderer.rs +34 -18
  143. package/src/rust/root.rs +50 -0
  144. package/src/rust/session/column_defaults_update.rs +4 -4
  145. package/src/rust/session/drag_drop_update.rs +1 -1
  146. package/src/rust/session/metadata.rs +3 -17
  147. package/src/rust/session/replace_expression_update.rs +1 -2
  148. package/src/rust/session.rs +162 -82
  149. package/src/rust/utils/browser/blob.rs +16 -2
  150. package/src/rust/utils/browser/download.rs +1 -0
  151. package/src/rust/{components/column_settings_sidebar/mod.rs → utils/browser/dragdrop.rs} +14 -5
  152. package/src/rust/utils/browser/mod.rs +8 -4
  153. package/src/rust/utils/browser/selection.rs +5 -0
  154. package/src/rust/utils/custom_element.rs +28 -13
  155. package/src/rust/utils/datetime.rs +5 -0
  156. package/src/rust/utils/debounce.rs +7 -1
  157. package/src/rust/utils/hooks/use_async_callback.rs +7 -17
  158. package/src/rust/utils/mod.rs +28 -40
  159. package/src/rust/utils/number_format.rs +6 -5
  160. package/src/rust/utils/pubsub.rs +15 -10
  161. package/src/rust/utils/weak_scope.rs +11 -1
  162. package/src/svg/bookmark-icon.svg +4 -0
  163. package/src/svg/drag-handle copy.svg +10 -0
  164. package/src/svg/drawer-tab-hover.svg +5 -7
  165. package/src/svg/drawer-tab-invert-hover.svg +4 -8
  166. package/src/svg/drawer-tab-invert.svg +4 -7
  167. package/src/svg/drawer-tab.svg +4 -6
  168. package/src/svg/status_ok.svg +24 -24
  169. package/src/ts/extensions.ts +51 -3
  170. package/src/ts/perspective-viewer.ts +2 -14
  171. package/src/ts/plugin.ts +1 -1
  172. package/src/ts/ts-rs/ViewerConfigUpdate.ts +1 -1
  173. package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +0 -177
  174. package/src/rust/components/containers/tests/mod.rs +0 -11
  175. package/src/rust/components/containers/tests/split_panel.rs +0 -91
  176. package/src/rust/js/testing.rs +0 -149
  177. package/src/rust/utils/tee.rs +0 -88
  178. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline0.js +0 -0
  179. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline1.js +0 -0
  180. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline2.js +0 -0
  181. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline3.js +0 -0
  182. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline4.js +0 -0
  183. /package/src/rust/components/{style_controls.rs → style_controls/mod.rs} +0 -0
  184. /package/src/rust/{components/containers → config}/kvpair.rs +0 -0
@@ -14,20 +14,17 @@ use perspective_client::config::{Expression, ViewConfigUpdate};
14
14
 
15
15
  use super::UpdateAndRender;
16
16
  use super::structural::*;
17
- use crate::components::column_settings_sidebar::ColumnSettingsTab;
18
- use crate::components::viewer::ColumnLocator;
19
- use crate::presentation::{OpenColumnSettings, Presentation};
17
+ use crate::presentation::{ColumnLocator, ColumnSettingsTab, OpenColumnSettings, Presentation};
20
18
  use crate::renderer::Renderer;
21
19
  use crate::session::Session;
22
20
  use crate::*;
23
21
 
24
- #[derive(PartialEq)]
22
+ #[derive(PartialEq, PerspectiveProperties!)]
25
23
  pub struct ExpressionUpdater {
26
24
  presentation: Presentation,
27
25
  renderer: Renderer,
28
26
  session: Session,
29
27
  }
30
- derive_model!(Presentation, Renderer, Session for ExpressionUpdater);
31
28
 
32
29
  pub trait EditExpression: HasPresentation + HasRenderer + HasSession + UpdateAndRender {
33
30
  fn get_expression_updater(&self) -> ExpressionUpdater {
@@ -0,0 +1,41 @@
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 perspective_client::clone;
14
+ use yew::Component;
15
+
16
+ use super::{HasRenderer, HasSession};
17
+ use crate::ApiFuture;
18
+ use crate::root::Root;
19
+ use crate::session::ResetOptions;
20
+
21
+ pub trait DeleteAll: HasSession + HasRenderer {
22
+ fn delete_all<T: Component>(&self, root: &Root<T>) -> ApiFuture<()> {
23
+ self.session().table_unloaded.emit(false);
24
+ clone!(self.renderer(), self.session(), root);
25
+ ApiFuture::new(self.renderer().clone().with_lock(async move {
26
+ renderer.delete()?;
27
+ root.borrow_mut().take().ok_or("Already deleted")?.destroy();
28
+ session
29
+ .reset(ResetOptions {
30
+ config: true,
31
+ expressions: true,
32
+ table: true,
33
+ ..ResetOptions::default()
34
+ })
35
+ .await?;
36
+ Ok(())
37
+ }))
38
+ }
39
+ }
40
+
41
+ impl<T: HasSession + HasRenderer> DeleteAll for T {}
@@ -16,9 +16,10 @@ static VERSION: &str = env!("CARGO_PKG_VERSION");
16
16
 
17
17
  fn render_plugin(tag_name: impl AsRef<str>) -> String {
18
18
  format!(
19
- "import \"https://cdn.jsdelivr.net/npm/@perspective-dev/{0}@{1}/dist/cdn/{0}.js\";\n",
19
+ "import \"https://cdn.jsdelivr.net/npm/@perspective-dev/{0}@{1}/dist/cdn/{2}.js\";\n",
20
+ tag_name.as_ref().replace("perspective-", ""),
21
+ VERSION,
20
22
  tag_name.as_ref(),
21
- VERSION
22
23
  )
23
24
  }
24
25
 
@@ -15,9 +15,6 @@ use perspective_client::config::ViewConfig;
15
15
  use super::columns_iter_set::*;
16
16
  use super::structural::*;
17
17
  use crate::config::*;
18
- use crate::presentation::Presentation;
19
- use crate::renderer::*;
20
- use crate::session::*;
21
18
  use crate::*;
22
19
 
23
20
  /// A `ViewerConfig` is constructed from various properties acrosss the
@@ -27,21 +24,7 @@ use crate::*;
27
24
  /// `GetViewerConfigModel` provides methods which should be used to get the
28
25
  /// applications `ViewerConfig` from across these state objects.
29
26
  pub trait GetViewerConfigModel: HasSession + HasRenderer + HasPresentation {
30
- /// As these methods are asynchronous, it is commonly useful to be able to
31
- /// discretely `.clone()` the state objects for dispatching to `async`.
32
- ///
33
- /// Calling `.cloned()` yields just the state object clones of
34
- /// `GetViewerConfigModel` which itself implements this trait and other
35
- /// `crate::model` traits.
36
- fn cloned(&self) -> GetViewerConfigModelCloned {
37
- GetViewerConfigModelCloned {
38
- renderer: self.renderer().clone(),
39
- session: self.session().clone(),
40
- presentation: self.presentation().clone(),
41
- }
42
- }
43
-
44
- /// Get the current ViewerConfig
27
+ /// Get the current [`ViewerConfig`]`
45
28
  async fn get_viewer_config(&self) -> ApiResult<ViewerConfig> {
46
29
  let version = config::API_VERSION.to_string();
47
30
  let view_config = self.session().get_view_config().clone();
@@ -50,7 +33,8 @@ pub trait GetViewerConfigModel: HasSession + HasRenderer + HasPresentation {
50
33
  let plugin = js_plugin.name();
51
34
  let plugin_config: serde_json::Value = js_plugin.save()?.into_serde_ext()?;
52
35
  let theme = self.presentation().get_selected_theme_name().await;
53
- let title = self.presentation().get_title();
36
+ let title = self.session().get_title();
37
+ let table = self.session().get_table().map(|x| x.get_name().to_owned());
54
38
  let columns_config = self.presentation().all_columns_configs();
55
39
  Ok(ViewerConfig {
56
40
  version,
@@ -59,6 +43,7 @@ pub trait GetViewerConfigModel: HasSession + HasRenderer + HasPresentation {
59
43
  plugin_config,
60
44
  columns_config,
61
45
  settings,
46
+ table,
62
47
  view_config,
63
48
  theme,
64
49
  })
@@ -67,15 +52,6 @@ pub trait GetViewerConfigModel: HasSession + HasRenderer + HasPresentation {
67
52
 
68
53
  impl<T: HasRenderer + HasSession + HasPresentation> GetViewerConfigModel for T {}
69
54
 
70
- #[derive(Clone)]
71
- pub struct GetViewerConfigModelCloned {
72
- renderer: Renderer,
73
- session: Session,
74
- presentation: Presentation,
75
- }
76
-
77
- derive_model!(Renderer, Session, Presentation for GetViewerConfigModelCloned);
78
-
79
55
  pub trait ColumnIteratorModel: HasSession + HasRenderer + HasDragDrop {
80
56
  fn column_selector_iter_set<'a>(&'a self, config: &'a ViewConfig) -> ColumnsIteratorSet<'a> {
81
57
  ColumnsIteratorSet::new(config, self.session(), self.renderer(), self.dragdrop())
@@ -10,13 +10,14 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- use perspective_client::config::ViewConfigUpdate;
14
13
  use wasm_bindgen::JsCast;
15
14
  use wasm_bindgen::prelude::*;
16
15
  use web_sys::*;
17
16
 
17
+ use crate::config::ViewerConfigUpdate;
18
18
  use crate::js::*;
19
19
  use crate::model::*;
20
+ use crate::presentation::Presentation;
20
21
  use crate::renderer::*;
21
22
  use crate::session::Session;
22
23
  use crate::utils::*;
@@ -29,16 +30,25 @@ pub struct IntersectionObserverHandle {
29
30
  }
30
31
 
31
32
  impl IntersectionObserverHandle {
32
- pub fn new(elem: &HtmlElement, session: &Session, renderer: &Renderer) -> Self {
33
- clone!(session, renderer);
33
+ pub fn new(
34
+ elem: &HtmlElement,
35
+ presentation: &Presentation,
36
+ session: &Session,
37
+ renderer: &Renderer,
38
+ ) -> Self {
39
+ clone!(session, renderer, presentation);
34
40
  let _callback = Closure::new(move |xs: js_sys::Array| {
35
41
  let intersect = xs
36
42
  .get(0)
37
43
  .unchecked_into::<IntersectionObserverEntry>()
38
44
  .is_intersecting();
39
45
 
40
- clone!(session, renderer);
41
- let state = IntersectionObserverState { session, renderer };
46
+ clone!(session, renderer, presentation);
47
+ let state = IntersectionObserverState {
48
+ presentation,
49
+ session,
50
+ renderer,
51
+ };
42
52
  ApiFuture::spawn(state.set_pause(intersect));
43
53
  });
44
54
 
@@ -59,16 +69,20 @@ impl Drop for IntersectionObserverHandle {
59
69
  }
60
70
  }
61
71
 
72
+ #[derive(PerspectiveProperties!)]
62
73
  struct IntersectionObserverState {
63
74
  session: Session,
64
75
  renderer: Renderer,
76
+ presentation: Presentation,
65
77
  }
66
78
 
67
79
  impl IntersectionObserverState {
68
80
  async fn set_pause(self, intersect: bool) -> ApiResult<()> {
69
81
  if intersect {
70
82
  if self.session.set_pause(false) {
71
- self.update_and_render(ViewConfigUpdate::default())?.await?;
83
+ self.presentation.visibility_changed.emit(intersect);
84
+ self.restore_and_render(ViewerConfigUpdate::default(), async move { Ok(()) })
85
+ .await?;
72
86
  }
73
87
  } else {
74
88
  self.session.set_pause(true);
@@ -77,5 +91,3 @@ impl IntersectionObserverState {
77
91
  Ok(())
78
92
  }
79
93
  }
80
-
81
- derive_model!(Renderer, Session for IntersectionObserverState);
@@ -30,23 +30,22 @@
30
30
  //! # Examples
31
31
  //!
32
32
  //! ```rust
33
+ //! #[derive(PerspectiveProperties!)]
33
34
  //! struct A {
34
35
  //! session: Session,
35
36
  //! }
36
37
  //!
38
+ //! #[derive(PerspectiveProperties!)]
37
39
  //! struct B {
38
40
  //! renderer: Renderer,
39
41
  //! }
40
42
  //!
43
+ //! #[derive(PerspectiveProperties!)]
41
44
  //! struct C {
42
45
  //! session: Session,
43
46
  //! renderer: Renderer,
44
47
  //! }
45
48
  //!
46
- //! derive_model!(Session for A);
47
- //! derive_model!(Renderer for B);
48
- //! derive_model!(Session, Renderer for C);
49
- //!
50
49
  //! trait SessionRenderModel: HasSession + HasRenderer {
51
50
  //! fn render_session_now(&self) {
52
51
  //! // Do some thing that requires `.session()` and `.renderer()`
@@ -65,29 +64,37 @@
65
64
  //! }
66
65
  //! ```
67
66
 
67
+ mod column_locator;
68
68
  mod columns_iter_set;
69
69
  mod copy_export;
70
70
  mod edit_expression;
71
+ mod eject;
71
72
  mod export_app;
72
73
  mod export_method;
73
74
  mod get_viewer_config;
74
75
  mod intersection_observer;
75
76
  mod is_invalid_drop;
76
77
  mod plugin_column_styles;
78
+ mod reset_all;
77
79
  mod resize_observer;
78
80
  mod restore_and_render;
81
+ mod send_plugin_config;
79
82
  mod structural;
80
83
  mod update_and_render;
81
84
 
85
+ pub use self::column_locator::*;
82
86
  pub use self::columns_iter_set::*;
83
87
  pub use self::copy_export::*;
84
88
  pub use self::edit_expression::*;
89
+ pub use self::eject::*;
85
90
  pub use self::export_method::*;
86
91
  pub use self::get_viewer_config::*;
87
92
  pub use self::intersection_observer::*;
88
93
  pub use self::is_invalid_drop::*;
89
94
  pub use self::plugin_column_styles::*;
95
+ pub use self::reset_all::*;
90
96
  pub use self::resize_observer::*;
91
97
  pub use self::restore_and_render::*;
98
+ pub use self::send_plugin_config::*;
92
99
  pub use self::structural::*;
93
100
  pub use self::update_and_render::*;
@@ -15,39 +15,8 @@ use perspective_js::utils::ApiResult;
15
15
 
16
16
  use super::{HasRenderer, HasSession};
17
17
  use crate::config::ColumnStyleOpts;
18
- use crate::derive_model;
19
- use crate::renderer::Renderer;
20
- use crate::session::Session;
21
-
22
- // TODO: This pattern of creating query objects to pass around would be
23
- // redundant if we had a grab-bag of models to clone around.
24
- // We could easily generate all the needed types for this in a proc_macro
25
- // crate. e.g. create structs like `SessionAndRendererModel {session,
26
- // renderer}` which are then called through a proc_macro like
27
- // `get_model!(Session, Renderer for self)` where the function is defined as
28
- // `get_model! => {($($name:ty),+ for $owner:ident)}`
29
- //
30
- // Or, we could just lump
31
- // all the state into a single object where all these model functions are
32
- // defined. Generally, we could keep the hub-and-spoke architecture "under the
33
- // hood", but just not expose it to the yew framework, since it requires a lot
34
- // of unecessary prop-drilling and complexity.
35
-
36
- #[derive(Clone)]
37
- pub struct PluginColumnStylesQuery {
38
- session: Session,
39
- renderer: Renderer,
40
- }
41
- derive_model!(Session, Renderer for PluginColumnStylesQuery);
42
18
 
43
19
  pub trait PluginColumnStyles: HasSession + HasRenderer {
44
- fn get_plugin_column_styles_query(&self) -> PluginColumnStylesQuery {
45
- PluginColumnStylesQuery {
46
- session: self.session().clone(),
47
- renderer: self.renderer().clone(),
48
- }
49
- }
50
-
51
20
  /// This function will query the plugin to see if a given column can render
52
21
  /// column styles.
53
22
  fn can_render_column_styles(&self, column_name: &str) -> ApiResult<bool> {
@@ -0,0 +1,38 @@
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 super::structural::*;
14
+ use crate::session::ResetOptions;
15
+ use crate::utils::*;
16
+ use crate::*;
17
+
18
+ pub trait ResetAll: HasRenderer + HasSession + HasPresentation {
19
+ /// Completely reset viewer state
20
+ fn reset_all(&self) -> ApiFuture<()> {
21
+ clone!(self.session(), self.renderer(), self.presentation());
22
+ ApiFuture::new(async move {
23
+ session
24
+ .reset(ResetOptions {
25
+ config: true,
26
+ expressions: true,
27
+ ..ResetOptions::default()
28
+ })
29
+ .await?;
30
+ presentation.reset_columns_configs();
31
+ renderer.reset(None).await?;
32
+ presentation.reset_available_themes(None).await;
33
+ Ok(())
34
+ })
35
+ }
36
+ }
37
+
38
+ impl<T: HasRenderer + HasSession + HasPresentation> ResetAll for T {}
@@ -16,9 +16,13 @@ use wasm_bindgen::prelude::*;
16
16
  use web_sys::*;
17
17
  use yew::prelude::*;
18
18
 
19
+ use crate::PerspectiveProperties;
19
20
  use crate::components::viewer::{PerspectiveViewer, PerspectiveViewerMsg};
20
21
  use crate::js::*;
22
+ use crate::model::*;
21
23
  use crate::renderer::*;
24
+ use crate::root::Root;
25
+ use crate::session::Session;
22
26
  use crate::utils::*;
23
27
 
24
28
  pub struct ResizeObserverHandle {
@@ -31,20 +35,26 @@ impl ResizeObserverHandle {
31
35
  pub fn new(
32
36
  elem: &HtmlElement,
33
37
  renderer: &Renderer,
34
- root: &AppHandle<PerspectiveViewer>,
38
+ session: &Session,
39
+ root: &Root<PerspectiveViewer>,
35
40
  ) -> Self {
36
- let on_resize = root.callback(|()| PerspectiveViewerMsg::Resize);
41
+ let on_resize = root
42
+ .borrow()
43
+ .as_ref()
44
+ .unwrap()
45
+ .callback(|()| PerspectiveViewerMsg::Resize);
46
+
37
47
  let mut state = ResizeObserverState {
38
48
  elem: elem.clone(),
39
49
  renderer: renderer.clone(),
50
+ session: session.clone(),
40
51
  width: elem.offset_width(),
41
52
  height: elem.offset_height(),
42
53
  on_resize,
43
54
  };
44
55
 
45
- let _callback = Closure::new(move |xs| state.on_resize(&xs));
46
- let func = _callback.as_ref().unchecked_ref::<js_sys::Function>();
47
- let observer = ResizeObserver::new(func);
56
+ let _callback = Closure::new(move |xs: js_sys::Array| state.on_resize(&xs));
57
+ let observer = ResizeObserver::new(_callback.as_ref().unchecked_ref::<js_sys::Function>());
48
58
  observer.observe(elem);
49
59
  Self {
50
60
  elem: elem.clone(),
@@ -60,9 +70,11 @@ impl Drop for ResizeObserverHandle {
60
70
  }
61
71
  }
62
72
 
73
+ #[derive(PerspectiveProperties!)]
63
74
  struct ResizeObserverState {
64
75
  elem: HtmlElement,
65
76
  renderer: Renderer,
77
+ session: Session,
66
78
  width: i32,
67
79
  height: i32,
68
80
  on_resize: Callback<()>,
@@ -83,9 +95,24 @@ impl ResizeObserverState {
83
95
  let content_height = content.height().floor() as i32;
84
96
  let resized = self.width != content_width || self.height != content_height;
85
97
  if resized && is_visible {
86
- clone!(self.on_resize, self.renderer);
98
+ let state = self.clone_state();
99
+ clone!(self.on_resize);
87
100
  ApiFuture::spawn(async move {
88
- renderer.resize().await?;
101
+ let needs_render = state
102
+ .renderer()
103
+ .clone()
104
+ .with_lock(async {
105
+ Ok(!state.renderer().is_plugin_activated()?
106
+ && state.session().has_table())
107
+ })
108
+ .await?;
109
+
110
+ if needs_render {
111
+ state.update_and_render(Default::default())?.await?;
112
+ } else {
113
+ state.renderer().resize().await?;
114
+ }
115
+
89
116
  on_resize.emit(());
90
117
  Ok(())
91
118
  });
@@ -35,16 +35,15 @@ pub trait RestoreAndRender: HasRenderer + HasSession + HasPresentation {
35
35
  ) -> ApiFuture<()> {
36
36
  clone!(self.session(), self.renderer(), self.presentation());
37
37
  ApiFuture::new(async move {
38
- if !session.has_table()
39
- && let OptionalUpdate::Update(x) = settings
40
- {
38
+ if let OptionalUpdate::Update(x) = settings {
41
39
  presentation.set_settings_attribute(x);
40
+ presentation.set_settings_before_open(x);
42
41
  }
43
42
 
44
43
  if let OptionalUpdate::Update(title) = title {
45
- presentation.set_title(Some(title));
44
+ session.set_title(Some(title));
46
45
  } else if matches!(title, OptionalUpdate::SetDefault) {
47
- presentation.set_title(None);
46
+ session.set_title(None);
48
47
  }
49
48
 
50
49
  let needs_restyle = match theme_name {
@@ -93,17 +92,23 @@ pub trait RestoreAndRender: HasRenderer + HasSession + HasPresentation {
93
92
  return Err(error);
94
93
  }
95
94
 
96
- session.validate().await?.create_view().await
95
+ let view = session.validate().await?.create_view().await;
96
+ if !presentation.is_visible() {
97
+ Ok(None)
98
+ } else {
99
+ view
100
+ }
97
101
  });
98
102
 
99
103
  draw_task.await?;
100
104
 
101
105
  // TODO this should be part of the API for `draw()` above, such that
102
106
  // the plugin need not render twice when a theme is provided.
103
- if needs_restyle {
107
+ if needs_restyle && presentation.is_visible() {
104
108
  let view = session.get_view().into_apierror()?;
105
109
  renderer.restyle_all(&view).await?;
106
110
  }
111
+ // }
107
112
 
108
113
  Ok(())
109
114
  })
@@ -10,45 +10,42 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- use extend::ext;
14
- use futures::channel::oneshot::*;
15
- use perspective_js::utils::ApiResult;
16
- use yew::html::Scope;
17
- use yew::prelude::*;
13
+ use perspective_js::utils::*;
18
14
 
19
- #[ext]
20
- pub impl<T> Scope<T>
21
- where
22
- T: Component,
23
- {
24
- /// Send a message with a callback, then suspend until the callback is
25
- /// invoked.
26
- fn send_message_async<F, U>(&self, f: F) -> Receiver<U>
27
- where
28
- F: FnOnce(Sender<U>) -> T::Message,
29
- {
30
- let (sender, receiver) = channel::<U>();
31
- self.send_message(f(sender));
32
- receiver
33
- }
15
+ use crate::config::ColumnConfigValueUpdate;
16
+ use crate::model::*;
17
+
18
+ pub trait SendPluginConfig {
19
+ /// Update te urrent plugin with a [`ColumnonfigValueUpdate`]
20
+ fn send_plugin_config(&self, column_name: &str, update: ColumnConfigValueUpdate);
34
21
  }
35
22
 
36
- #[ext]
37
- pub(crate) impl<T> Callback<Sender<T>>
23
+ impl<A> SendPluginConfig for A
38
24
  where
39
- T: 'static,
25
+ A: Clone + HasCustomEvents + HasPresentation + HasRenderer + HasSession + 'static,
40
26
  {
41
- /// This is "safe" because `emit()` is not called synchronously. Normally
42
- /// we want this to minimize the async by doing as much work synchronous
43
- /// as possible (see `send_message_async()` e.g.), but this method calls
44
- /// `Yew` which _never_ wants to be called synchronously.
45
- ///
46
- /// TODO Need test coverage for this - error behavior is that presize/render
47
- /// blocking calls are out-of-order, e.g. toggle config `presize()` call.
48
- /// Engineering the test to capture this faulty behavior may be difficult
49
- async fn emit_async_safe(&self) -> ApiResult<T> {
50
- let (sender, receiver) = channel::<T>();
51
- self.emit(sender);
52
- Ok(receiver.await?)
27
+ fn send_plugin_config(&self, column_name: &str, update: ColumnConfigValueUpdate) {
28
+ let name = column_name.to_string();
29
+ let props = self.clone();
30
+ ApiFuture::spawn(async move {
31
+ props
32
+ .presentation()
33
+ .update_columns_config_value(name.clone(), update);
34
+
35
+ let columns_configs = props.presentation().all_columns_configs();
36
+ let plugin_config = props.renderer().get_active_plugin()?.save()?;
37
+ props
38
+ .renderer()
39
+ .get_active_plugin()?
40
+ .restore(&plugin_config, Some(&columns_configs))?;
41
+
42
+ props.renderer().update(props.session().get_view()).await?;
43
+ let detail = serde_wasm_bindgen::to_value(&columns_configs).unwrap();
44
+ props
45
+ .custom_events()
46
+ .dispatch_column_style_changed(&detail)?;
47
+
48
+ Ok(())
49
+ })
53
50
  }
54
51
  }