@perspective-dev/viewer 4.4.1 → 4.5.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 (225) hide show
  1. package/dist/cdn/perspective-viewer.js +1 -2
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/botanical.css +1 -1
  4. package/dist/css/dracula.css +1 -1
  5. package/dist/css/gruvbox-dark.css +1 -1
  6. package/dist/css/gruvbox.css +1 -1
  7. package/dist/css/icons.css +1 -1
  8. package/dist/css/intl/de.css +1 -1
  9. package/dist/css/intl/es.css +1 -1
  10. package/dist/css/intl/fr.css +1 -1
  11. package/dist/css/intl/ja.css +1 -1
  12. package/dist/css/intl/pt.css +1 -1
  13. package/dist/css/intl/zh.css +1 -1
  14. package/dist/css/intl.css +1 -1
  15. package/dist/css/monokai.css +1 -1
  16. package/dist/css/phosphor.css +1 -1
  17. package/dist/css/pro-dark.css +1 -1
  18. package/dist/css/pro.css +1 -1
  19. package/dist/css/solarized-dark.css +1 -1
  20. package/dist/css/solarized.css +1 -1
  21. package/dist/css/themes.css +1 -1
  22. package/dist/css/vaporwave.css +1 -1
  23. package/dist/esm/bootstrap.d.ts +2 -1
  24. package/dist/esm/column-format.d.ts +51 -0
  25. package/dist/esm/extensions.d.ts +2 -0
  26. package/dist/esm/perspective-viewer.d.ts +3 -1
  27. package/dist/esm/perspective-viewer.inline.js +1 -2
  28. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  29. package/dist/esm/perspective-viewer.js +1 -2
  30. package/dist/esm/perspective-viewer.js.map +4 -4
  31. package/dist/esm/perspective-viewer.worker.d.ts +2 -0
  32. package/dist/esm/plugin.d.ts +16 -72
  33. package/dist/esm/ts-rs/ColumnSelectMode.d.ts +1 -0
  34. package/dist/esm/ts-rs/PluginStaticConfig.d.ts +77 -0
  35. package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -3
  36. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +7 -4
  37. package/dist/wasm/perspective-viewer.d.ts +77 -18
  38. package/dist/wasm/perspective-viewer.js +293 -144
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +20 -15
  41. package/package.json +24 -2
  42. package/src/css/column-selector.css +3 -2
  43. package/src/css/column-settings-panel.css +35 -6
  44. package/src/css/column-style.css +27 -2
  45. package/src/css/containers/scroll-panel.css +2 -1
  46. package/src/css/containers/tabs.css +8 -52
  47. package/src/css/dom/checkbox.css +0 -4
  48. package/src/css/form/code-editor.css +1 -0
  49. package/src/css/form/debug.css +3 -10
  50. package/src/css/plugin-selector.css +33 -0
  51. package/src/css/plugin-settings-panel.css +99 -0
  52. package/src/css/viewer.css +65 -3
  53. package/src/rust/components/column_dropdown.rs +3 -1
  54. package/src/rust/components/column_selector/active_column.rs +13 -19
  55. package/src/rust/components/column_selector/config_selector.rs +20 -20
  56. package/src/rust/components/column_selector/filter_column.rs +14 -14
  57. package/src/rust/components/column_selector/inactive_column.rs +9 -15
  58. package/src/rust/components/column_selector/pivot_column.rs +7 -7
  59. package/src/rust/components/column_selector/sort_column.rs +7 -7
  60. package/src/rust/components/column_selector.rs +55 -37
  61. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +15 -7
  62. package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +394 -0
  63. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +15 -6
  64. package/src/rust/components/column_settings_sidebar/style_tab.rs +267 -136
  65. package/src/rust/components/column_settings_sidebar.rs +43 -49
  66. package/src/rust/components/containers/dragdrop_list.rs +5 -5
  67. package/src/rust/components/containers/mod.rs +0 -1
  68. package/src/rust/components/containers/scroll_panel.rs +21 -7
  69. package/src/rust/components/containers/sidebar.rs +8 -6
  70. package/src/rust/components/containers/split_panel.rs +3 -3
  71. package/src/rust/components/containers/tab_list.rs +3 -9
  72. package/src/rust/components/copy_dropdown.rs +2 -3
  73. package/src/rust/components/datetime_column_style.rs +19 -81
  74. package/src/rust/components/editable_header.rs +2 -3
  75. package/src/rust/components/export_dropdown.rs +2 -3
  76. package/src/rust/components/expression_editor.rs +29 -17
  77. package/src/rust/components/filter_dropdown.rs +2 -1
  78. package/src/rust/components/form/color_range_selector.rs +14 -7
  79. package/src/rust/components/form/debug.rs +47 -37
  80. package/src/rust/components/main_panel.rs +24 -65
  81. package/src/rust/components/mod.rs +2 -1
  82. package/src/rust/components/number_series_style.rs +161 -0
  83. package/src/rust/components/plugin_tab.rs +221 -0
  84. package/src/rust/components/settings_panel.rs +181 -59
  85. package/src/rust/components/status_bar.rs +140 -173
  86. package/src/rust/components/status_indicator.rs +15 -22
  87. package/src/rust/components/string_column_style.rs +20 -82
  88. package/src/rust/components/style_controls/number_string_format.rs +14 -30
  89. package/src/rust/components/viewer.rs +92 -131
  90. package/src/rust/config/column_config_schema.rs +195 -0
  91. package/src/rust/config/columns_config.rs +4 -97
  92. package/src/rust/config/datetime_column_style.rs +0 -5
  93. package/src/rust/config/mod.rs +8 -2
  94. package/src/rust/config/number_series_style.rs +79 -0
  95. package/src/rust/config/plugin_static_config.rs +144 -0
  96. package/src/rust/config/string_column_style.rs +0 -5
  97. package/src/rust/config/viewer_config.rs +5 -6
  98. package/src/rust/custom_elements/copy_dropdown.rs +30 -18
  99. package/src/rust/custom_elements/debug_plugin.rs +1 -3
  100. package/src/rust/custom_elements/export_dropdown.rs +26 -18
  101. package/src/rust/custom_elements/viewer.rs +62 -73
  102. package/src/rust/custom_events.rs +181 -224
  103. package/src/rust/js/plugin.rs +45 -117
  104. package/src/rust/lib.rs +34 -5
  105. package/src/rust/presentation/drag_helpers.rs +206 -0
  106. package/src/rust/presentation/props.rs +8 -0
  107. package/src/rust/presentation.rs +256 -41
  108. package/src/rust/{tasks → queries}/column_locator.rs +17 -73
  109. package/src/rust/queries/column_values.rs +59 -0
  110. package/src/rust/{tasks → queries}/columns_iter_set.rs +11 -18
  111. package/src/rust/queries/exports.rs +96 -0
  112. package/src/rust/queries/fetch_column_stats.rs +94 -0
  113. package/src/rust/queries/get_viewer_config.rs +54 -0
  114. package/src/rust/queries/mod.rs +44 -0
  115. package/src/rust/queries/plugin_column_styles.rs +101 -0
  116. package/src/rust/{engines.rs → queries/validate_expression.rs} +26 -15
  117. package/src/rust/renderer/activate.rs +1 -0
  118. package/src/rust/renderer/limits.rs +9 -4
  119. package/src/rust/renderer/plugin_store.rs +12 -0
  120. package/src/rust/renderer/props.rs +28 -3
  121. package/src/rust/renderer/registry.rs +40 -15
  122. package/src/rust/renderer.rs +640 -51
  123. package/src/rust/session/column_defaults_update.rs +20 -28
  124. package/src/rust/session/drag_drop_update.rs +10 -10
  125. package/src/rust/session/metadata.rs +31 -16
  126. package/src/rust/session/props.rs +15 -6
  127. package/src/rust/session/view_subscription.rs +10 -0
  128. package/src/rust/session.rs +109 -147
  129. package/src/rust/tasks/copy_export.rs +178 -158
  130. package/src/rust/tasks/{structural.rs → dismiss_render_warning.rs} +20 -40
  131. package/src/rust/tasks/edit_expression.rs +68 -88
  132. package/src/rust/tasks/eject.rs +25 -22
  133. package/src/rust/tasks/intersection_observer.rs +8 -21
  134. package/src/rust/tasks/mod.rs +19 -21
  135. package/src/rust/tasks/reset_all.rs +78 -0
  136. package/src/rust/tasks/resize_observer.rs +11 -33
  137. package/src/rust/tasks/restore_and_render.rs +117 -90
  138. package/src/rust/tasks/{get_viewer_config.rs → send_column_config.rs} +38 -35
  139. package/src/rust/tasks/send_plugin_config.rs +32 -33
  140. package/src/rust/tasks/update_and_render.rs +66 -47
  141. package/src/rust/{components/containers/trap_door_panel.rs → tasks/update_theme.rs} +34 -33
  142. package/src/rust/tasks/validate_expression.rs +61 -0
  143. package/src/rust/utils/browser/selection.rs +4 -4
  144. package/src/rust/utils/mod.rs +0 -63
  145. package/src/svg/mega-menu-icons-density.svg +23 -0
  146. package/src/svg/mega-menu-icons-map-density.svg +24 -0
  147. package/src/svg/mega-menu-icons-map-line.svg +19 -0
  148. package/src/themes/botanical.css +27 -53
  149. package/src/themes/defaults.css +24 -36
  150. package/src/themes/dracula.css +36 -54
  151. package/src/themes/gruvbox-dark.css +39 -59
  152. package/src/themes/gruvbox.css +16 -28
  153. package/src/themes/icons.css +3 -0
  154. package/src/themes/intl/de.css +42 -6
  155. package/src/themes/intl/es.css +42 -6
  156. package/src/themes/intl/fr.css +42 -6
  157. package/src/themes/intl/ja.css +42 -6
  158. package/src/themes/intl/pt.css +42 -6
  159. package/src/themes/intl/zh.css +42 -6
  160. package/src/themes/intl.css +37 -4
  161. package/src/themes/monokai.css +45 -61
  162. package/src/themes/phosphor.css +20 -29
  163. package/src/themes/pro-dark.css +25 -34
  164. package/src/themes/solarized-dark.css +21 -36
  165. package/src/themes/solarized.css +13 -23
  166. package/src/themes/vaporwave.css +40 -74
  167. package/src/ts/bootstrap.ts +14 -3
  168. package/src/ts/column-format.ts +162 -0
  169. package/src/ts/extensions.ts +4 -0
  170. package/src/ts/perspective-viewer.ts +9 -1
  171. package/src/{rust/components/column_settings_sidebar/style_tab/stub.rs → ts/perspective-viewer.worker.ts} +2 -22
  172. package/src/ts/plugin.ts +25 -101
  173. package/src/ts/ts-rs/{FormatUnit.ts → ColumnSelectMode.ts} +1 -1
  174. package/src/ts/ts-rs/PluginStaticConfig.ts +78 -0
  175. package/src/ts/ts-rs/ViewerConfig.ts +1 -2
  176. package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -3
  177. package/dist/esm/ts-rs/ColumnConfigValues.d.ts +0 -31
  178. package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +0 -1
  179. package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +0 -15
  180. package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +0 -18
  181. package/dist/esm/ts-rs/DatetimeColorMode.d.ts +0 -1
  182. package/dist/esm/ts-rs/DatetimeFormatType.d.ts +0 -6
  183. package/dist/esm/ts-rs/FormatMode.d.ts +0 -1
  184. package/dist/esm/ts-rs/FormatUnit.d.ts +0 -1
  185. package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +0 -1
  186. package/dist/esm/ts-rs/NumberForegroundMode.d.ts +0 -1
  187. package/dist/esm/ts-rs/PluginConfig.d.ts +0 -2
  188. package/dist/esm/ts-rs/RoundingMode.d.ts +0 -1
  189. package/dist/esm/ts-rs/RoundingPriority.d.ts +0 -1
  190. package/dist/esm/ts-rs/SignDisplay.d.ts +0 -1
  191. package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +0 -1
  192. package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +0 -6
  193. package/dist/esm/ts-rs/StringColorMode.d.ts +0 -1
  194. package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +0 -1
  195. package/dist/esm/ts-rs/UseGrouping.d.ts +0 -1
  196. package/src/rust/components/number_column_style.rs +0 -491
  197. package/src/rust/config/number_column_style.rs +0 -136
  198. package/src/rust/dragdrop.rs +0 -481
  199. package/src/rust/tasks/plugin_column_styles.rs +0 -98
  200. package/src/ts/ts-rs/ColumnConfigValues.ts +0 -14
  201. package/src/ts/ts-rs/CustomDatetimeFormat.ts +0 -3
  202. package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +0 -5
  203. package/src/ts/ts-rs/CustomNumberFormatConfig.ts +0 -8
  204. package/src/ts/ts-rs/DatetimeColorMode.ts +0 -3
  205. package/src/ts/ts-rs/DatetimeFormatType.ts +0 -8
  206. package/src/ts/ts-rs/FormatMode.ts +0 -3
  207. package/src/ts/ts-rs/NumberBackgroundMode.ts +0 -3
  208. package/src/ts/ts-rs/NumberForegroundMode.ts +0 -3
  209. package/src/ts/ts-rs/PluginConfig.ts +0 -4
  210. package/src/ts/ts-rs/RoundingMode.ts +0 -3
  211. package/src/ts/ts-rs/RoundingPriority.ts +0 -3
  212. package/src/ts/ts-rs/SignDisplay.ts +0 -3
  213. package/src/ts/ts-rs/SimpleDatetimeFormat.ts +0 -3
  214. package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +0 -4
  215. package/src/ts/ts-rs/StringColorMode.ts +0 -3
  216. package/src/ts/ts-rs/TrailingZeroDisplay.ts +0 -3
  217. package/src/ts/ts-rs/UseGrouping.ts +0 -3
  218. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-39ab7da3ca157861}/inline0.js +0 -0
  219. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-39ab7da3ca157861}/inline1.js +0 -0
  220. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-39ab7da3ca157861}/inline2.js +0 -0
  221. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-39ab7da3ca157861}/inline3.js +0 -0
  222. /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-39ab7da3ca157861}/inline4.js +0 -0
  223. /package/src/rust/{tasks → config}/export_method.rs +0 -0
  224. /package/src/rust/{tasks → queries}/export_app.rs +0 -0
  225. /package/src/rust/{tasks → queries}/is_invalid_drop.rs +0 -0
@@ -23,8 +23,11 @@ use super::viewer::PerspectiveViewerElement;
23
23
  use crate::components::copy_dropdown::CopyDropDownMenu;
24
24
  use crate::components::portal::PortalModal;
25
25
  use crate::components::style::StyleProvider;
26
+ use crate::config::*;
26
27
  use crate::js::*;
28
+ use crate::presentation::Presentation;
27
29
  use crate::renderer::*;
30
+ use crate::session::Session;
28
31
  use crate::tasks::*;
29
32
  use crate::utils::*;
30
33
  use crate::*;
@@ -130,57 +133,66 @@ impl CopyDropDownMenuElement {
130
133
  }
131
134
 
132
135
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
133
- self.set_config_model(parent)
136
+ self.set_config_model(&parent.session, &parent.renderer, &parent.presentation)
134
137
  }
135
138
 
136
139
  pub fn connected_callback(&self) {}
137
140
  }
138
141
 
139
142
  impl CopyDropDownMenuElement {
140
- pub fn new_from_model<A>(model: &A) -> Self
141
- where
142
- A: GetViewerConfigModel + StateProvider,
143
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
144
- {
143
+ pub fn new_from_model(
144
+ session: &Session,
145
+ renderer: &Renderer,
146
+ presentation: &Presentation,
147
+ ) -> Self {
145
148
  let dropdown = global::document()
146
149
  .create_element("perspective-copy-menu")
147
150
  .unwrap()
148
151
  .unchecked_into::<HtmlElement>();
149
152
 
150
153
  let elem = Self::new(dropdown);
151
- elem.set_config_model(model);
154
+ elem.set_config_model(session, renderer, presentation);
152
155
  elem
153
156
  }
154
157
 
155
- pub fn set_config_model<A>(&self, model: &A)
156
- where
157
- A: GetViewerConfigModel + StateProvider,
158
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
159
- {
158
+ pub fn set_config_model(
159
+ &self,
160
+ session: &Session,
161
+ renderer: &Renderer,
162
+ presentation: &Presentation,
163
+ ) {
160
164
  let callback = Callback::from({
161
- let model = model.clone_state();
165
+ let session = session.clone();
166
+ let renderer = renderer.clone();
167
+ let presentation = presentation.clone();
162
168
  let target = self.target.clone();
163
169
  let root = self.root.clone();
164
170
  move |x: ExportFile| {
165
- let model = model.clone();
171
+ let session = session.clone();
172
+ let renderer = renderer.clone();
173
+ let presentation = presentation.clone();
166
174
  let target = target.clone();
167
175
  let root = root.clone();
168
176
  spawn_local(async move {
169
177
  let mime = x.method.mimetype(x.is_chart);
170
- let task = model.export_method_to_blob(x.method);
178
+ let task = export_method_to_blob(&session, &renderer, &presentation, x.method);
171
179
  let result = copy_to_clipboard(task, mime).await;
172
- crate::maybe_log!({
180
+ let r = (|| -> ApiResult<()> {
173
181
  result?;
174
182
  *target.borrow_mut() = None;
175
183
  if let Some(root) = root.borrow().as_ref() {
176
184
  root.send_message(CopyDropDownWrapperMsg::Close);
177
185
  }
178
- })
186
+ Ok(())
187
+ })();
188
+ if let Err(e) = r {
189
+ web_sys::console::warn_1(&e.into());
190
+ }
179
191
  })
180
192
  }
181
193
  });
182
194
 
183
- let renderer = model.renderer().clone();
195
+ let renderer = renderer.clone();
184
196
  let init = ShadowRootInit::new(ShadowRootMode::Open);
185
197
  let shadow_root = self
186
198
  .elem
@@ -93,9 +93,7 @@ impl PerspectiveDebugPluginElement {
93
93
  ApiFuture::default()
94
94
  }
95
95
 
96
- pub fn restyle(&self) -> ApiFuture<()> {
97
- ApiFuture::default()
98
- }
96
+ pub fn restyle(&self) {}
99
97
 
100
98
  pub fn save(&self) -> ApiResult<JsValue> {
101
99
  Ok(JsValue::null())
@@ -23,6 +23,8 @@ use super::viewer::PerspectiveViewerElement;
23
23
  use crate::components::export_dropdown::ExportDropDownMenu;
24
24
  use crate::components::portal::PortalModal;
25
25
  use crate::components::style::StyleProvider;
26
+ use crate::config::*;
27
+ use crate::presentation::Presentation;
26
28
  use crate::renderer::*;
27
29
  use crate::session::*;
28
30
  use crate::tasks::*;
@@ -132,43 +134,49 @@ impl ExportDropDownMenuElement {
132
134
  }
133
135
 
134
136
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
135
- self.set_config_model(parent)
137
+ self.set_config_model(&parent.session, &parent.renderer, &parent.presentation)
136
138
  }
137
139
 
138
140
  pub fn connected_callback(&self) {}
139
141
  }
140
142
 
141
143
  impl ExportDropDownMenuElement {
142
- pub fn new_from_model<A>(model: &A) -> Self
143
- where
144
- A: GetViewerConfigModel + StateProvider,
145
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
146
- {
144
+ pub fn new_from_model(
145
+ session: &Session,
146
+ renderer: &Renderer,
147
+ presentation: &Presentation,
148
+ ) -> Self {
147
149
  let dropdown = global::document()
148
150
  .create_element("perspective-export-menu")
149
151
  .unwrap()
150
152
  .unchecked_into::<HtmlElement>();
151
153
 
152
154
  let elem = Self::new(dropdown);
153
- elem.set_config_model(model);
155
+ elem.set_config_model(session, renderer, presentation);
154
156
  elem
155
157
  }
156
158
 
157
- fn set_config_model<A>(&self, model: &A)
158
- where
159
- A: GetViewerConfigModel + StateProvider,
160
- <A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
161
- {
159
+ fn set_config_model(
160
+ &self,
161
+ session: &Session,
162
+ renderer: &Renderer,
163
+ presentation: &Presentation,
164
+ ) {
162
165
  let callback = Callback::from({
163
- let model = model.clone_state();
166
+ let session = session.clone();
167
+ let renderer = renderer.clone();
168
+ let presentation = presentation.clone();
164
169
  let target = self.target.clone();
165
170
  let root = self.root.clone();
166
171
  move |x: ExportFile| {
167
172
  if !x.name.is_empty() {
168
- clone!(target, root, model);
173
+ clone!(target, root, session, renderer, presentation);
169
174
  spawn_local(async move {
170
- let val = model.export_method_to_blob(x.method).await.unwrap();
171
- let is_chart = model.renderer().is_chart();
175
+ let val =
176
+ export_method_to_blob(&session, &renderer, &presentation, x.method)
177
+ .await
178
+ .unwrap();
179
+ let is_chart = renderer.is_chart();
172
180
  download(&x.as_filename(is_chart), &val).unwrap();
173
181
  *target.borrow_mut() = None;
174
182
  if let Some(root) = root.borrow().as_ref() {
@@ -179,8 +187,8 @@ impl ExportDropDownMenuElement {
179
187
  }
180
188
  });
181
189
 
182
- let renderer = model.renderer().clone();
183
- let session = model.session().clone();
190
+ let renderer = renderer.clone();
191
+ let session = session.clone();
184
192
  let init = ShadowRootInit::new(ShadowRootMode::Open);
185
193
  let shadow_root = self
186
194
  .elem
@@ -29,9 +29,9 @@ use web_sys::HtmlElement;
29
29
  use crate::components::viewer::{PerspectiveViewerMsg, PerspectiveViewerProps};
30
30
  use crate::config::*;
31
31
  use crate::custom_events::*;
32
- use crate::dragdrop::*;
33
32
  use crate::js::*;
34
33
  use crate::presentation::*;
34
+ use crate::queries::*;
35
35
  use crate::renderer::*;
36
36
  use crate::root::Root;
37
37
  use crate::session::{ResetOptions, Session, TableLoadState};
@@ -90,48 +90,17 @@ pub struct PerspectiveViewerElement {
90
90
  root: Root<components::viewer::PerspectiveViewer>,
91
91
  resize_handle: Rc<RefCell<Option<ResizeObserverHandle>>>,
92
92
  intersection_handle: Rc<RefCell<Option<IntersectionObserverHandle>>>,
93
- session: Session,
94
- renderer: Renderer,
95
- presentation: Presentation,
96
- custom_events: CustomEvents,
93
+ pub(crate) session: Session,
94
+ pub(crate) renderer: Renderer,
95
+ pub(crate) presentation: Presentation,
97
96
  _subscriptions: Rc<[Subscription; 2]>,
98
- }
99
-
100
- impl HasCustomEvents for PerspectiveViewerElement {
101
- fn custom_events(&self) -> &CustomEvents {
102
- &self.custom_events
103
- }
104
- }
105
-
106
- impl HasPresentation for PerspectiveViewerElement {
107
- fn presentation(&self) -> &Presentation {
108
- &self.presentation
109
- }
110
- }
111
-
112
- impl HasRenderer for PerspectiveViewerElement {
113
- fn renderer(&self) -> &Renderer {
114
- &self.renderer
115
- }
116
- }
117
-
118
- impl HasSession for PerspectiveViewerElement {
119
- fn session(&self) -> &Session {
120
- &self.session
121
- }
122
- }
123
-
124
- impl StateProvider for PerspectiveViewerElement {
125
- type State = PerspectiveViewerElement;
126
-
127
- fn clone_state(&self) -> Self::State {
128
- self.clone()
129
- }
97
+ _custom_event_subs: Rc<Vec<Subscription>>,
130
98
  }
131
99
 
132
100
  impl CustomElementMetadata for PerspectiveViewerElement {
133
101
  const CUSTOM_ELEMENT_NAME: &'static str = "perspective-viewer";
134
- const STATICS: &'static [&'static str] = ["registerPlugin"].as_slice();
102
+ const STATICS: &'static [&'static str] =
103
+ ["registerPlugin", "get_wasm_module", "get_worker_url"].as_slice();
135
104
  }
136
105
 
137
106
  #[wasm_bindgen]
@@ -153,7 +122,7 @@ impl PerspectiveViewerElement {
153
122
  let session = Session::new();
154
123
  let renderer = Renderer::new(&elem);
155
124
  let presentation = Presentation::new(&elem);
156
- let custom_events = CustomEvents::new(&elem, &session, &renderer, &presentation);
125
+ let custom_event_subs = wire_custom_events(&elem, &session, &renderer, &presentation);
157
126
 
158
127
  // Create Yew App
159
128
  let props = yew::props!(PerspectiveViewerProps {
@@ -161,11 +130,9 @@ impl PerspectiveViewerElement {
161
130
  session: session.clone(),
162
131
  renderer: renderer.clone(),
163
132
  presentation: presentation.clone(),
164
- dragdrop: DragDrop::new(&elem),
165
- custom_events: custom_events.clone(),
166
133
  });
167
134
 
168
- let state = props.clone_state();
135
+ let state = props.clone();
169
136
  let root = Root::new(shadow_root, props);
170
137
 
171
138
  // Create callbacks
@@ -185,7 +152,7 @@ impl PerspectiveViewerElement {
185
152
 
186
153
  let eject_sub = presentation.on_eject.add_listener({
187
154
  let root = root.clone();
188
- move |_| ApiFuture::spawn(state.delete_all(&root))
155
+ move |_| ApiFuture::spawn(delete_all(&state.session, &state.renderer, &root))
189
156
  });
190
157
 
191
158
  let resize_handle =
@@ -202,8 +169,8 @@ impl PerspectiveViewerElement {
202
169
  presentation,
203
170
  resize_handle: Rc::new(RefCell::new(Some(resize_handle))),
204
171
  intersection_handle: Rc::new(RefCell::new(Some(intersect_handle))),
205
- custom_events,
206
172
  _subscriptions: Rc::new([update_sub, eject_sub]),
173
+ _custom_event_subs: Rc::new(custom_event_subs),
207
174
  }
208
175
  }
209
176
 
@@ -370,7 +337,7 @@ impl PerspectiveViewerElement {
370
337
  /// await viewer.delete();
371
338
  /// ```
372
339
  pub fn delete(self) -> ApiFuture<()> {
373
- self.delete_all(&self.root)
340
+ delete_all(&self.session, &self.renderer, &self.root)
374
341
  }
375
342
 
376
343
  /// Restart this `<perspective-viewer>` to its initial state, before
@@ -423,12 +390,24 @@ impl PerspectiveViewerElement {
423
390
  /// [`PerspectiveViewerElement::save`]), and also makes no API calls to the
424
391
  /// server (unlike [`PerspectiveViewerElement::getView`] followed by
425
392
  /// [`View::get_config`])
393
+ ///
394
+ /// Returns the [`ViewConfig`] the currently-bound `View` was constructed
395
+ /// from, so the value is consistent with what the active plugin is
396
+ /// rendering even if a queued [`Self::restore`]/`update_and_render` has
397
+ /// already mutated the live config in anticipation of the next draw.
398
+ /// Falls back to the live session config when no `View` has yet been
399
+ /// created (e.g., after `load` but before the first render).
426
400
  #[wasm_bindgen]
427
401
  pub fn getViewConfig(&self) -> ApiFuture<JsViewConfig> {
428
402
  let session = self.session.clone();
429
403
  ApiFuture::new(async move {
430
- let config = session.get_view_config();
431
- Ok(JsValue::from_serde_ext(&*config)?.unchecked_into())
404
+ let config = if let Some(rendered) = session.get_rendered_view_config() {
405
+ (*rendered).clone()
406
+ } else {
407
+ session.get_view_config().clone()
408
+ };
409
+
410
+ Ok(JsValue::from_serde_ext(&config)?.unchecked_into())
432
411
  })
433
412
  }
434
413
 
@@ -595,8 +574,12 @@ impl PerspectiveViewerElement {
595
574
  None
596
575
  };
597
576
 
598
- let result = this
599
- .restore_and_render(decoded_update.clone(), {
577
+ let result = restore_and_render(
578
+ &this.session,
579
+ &this.renderer,
580
+ &this.presentation,
581
+ decoded_update.clone(),
582
+ {
600
583
  clone!(this, decoded_update.table);
601
584
  async move {
602
585
  if let OptionalUpdate::Update(name) = table {
@@ -614,11 +597,12 @@ impl PerspectiveViewerElement {
614
597
  receiver.await.unwrap_or_log();
615
598
  Ok(())
616
599
  }
617
- })
618
- .await;
600
+ },
601
+ )
602
+ .await;
619
603
 
620
604
  if let Err(e) = &result {
621
- this.session().set_error(false, e.clone()).await?;
605
+ this.session.set_error(false, e.clone()).await?;
622
606
  }
623
607
  result
624
608
  })
@@ -631,7 +615,7 @@ impl PerspectiveViewerElement {
631
615
  ApiFuture::spawn(self.session.reset(ResetOptions::default()));
632
616
  let this = self.clone();
633
617
  ApiFuture::new_throttled(async move {
634
- this.update_and_render(ViewConfigUpdate::default())?.await?;
618
+ update_and_render(&this.session, &this.renderer, ViewConfigUpdate::default())?.await?;
635
619
  Ok(())
636
620
  })
637
621
  }
@@ -661,7 +645,9 @@ impl PerspectiveViewerElement {
661
645
  let viewer_config = this
662
646
  .renderer
663
647
  .clone()
664
- .with_lock(async { this.get_viewer_config().await })
648
+ .with_lock(async {
649
+ get_viewer_config(&this.session, &this.renderer, &this.presentation).await
650
+ })
665
651
  .await?;
666
652
 
667
653
  viewer_config.encode()
@@ -696,7 +682,9 @@ impl PerspectiveViewerElement {
696
682
  ExportMethod::Csv
697
683
  };
698
684
 
699
- let blob = this.export_method_to_blob(method).await?;
685
+ let blob =
686
+ export_method_to_blob(&this.session, &this.renderer, &this.presentation, method)
687
+ .await?;
700
688
  let is_chart = this.renderer.is_chart();
701
689
  download(
702
690
  format!("untitled{}", method.as_filename(is_chart)).as_ref(),
@@ -711,7 +699,7 @@ impl PerspectiveViewerElement {
711
699
  ///
712
700
  /// This method is only really useful for the `"plugin"` method, which
713
701
  /// will use the configured plugin's export (e.g. PNG for
714
- /// `@perspective-dev/viewer-d3fc`). Otherwise, prefer to call the
702
+ /// `@perspective-dev/viewer-charts`). Otherwise, prefer to call the
715
703
  /// equivalent method on the underlying [`View`] directly.
716
704
  ///
717
705
  /// # Arguments
@@ -735,7 +723,8 @@ impl PerspectiveViewerElement {
735
723
  ExportMethod::Csv
736
724
  };
737
725
 
738
- this.export_method_to_jsvalue(method).await
726
+ export_method_to_jsvalue(&this.session, &this.renderer, &this.presentation, method)
727
+ .await
739
728
  })
740
729
  }
741
730
 
@@ -766,7 +755,8 @@ impl PerspectiveViewerElement {
766
755
  ExportMethod::Csv
767
756
  };
768
757
 
769
- let js_task = this.export_method_to_blob(method);
758
+ let js_task =
759
+ export_method_to_blob(&this.session, &this.renderer, &this.presentation, method);
770
760
  copy_to_clipboard(js_task, MimeType::TextPlain).await
771
761
  })
772
762
  }
@@ -827,19 +817,18 @@ impl PerspectiveViewerElement {
827
817
  .unwrap_or_default()
828
818
  .unwrap_or_default();
829
819
 
830
- let state = self.clone_state();
820
+ let state = self.clone();
831
821
  ApiFuture::new_throttled(async move {
832
- if !state.renderer().is_plugin_activated()? {
833
- state
834
- .update_and_render(ViewConfigUpdate::default())?
822
+ if !state.renderer.is_plugin_activated()? {
823
+ update_and_render(&state.session, &state.renderer, ViewConfigUpdate::default())?
835
824
  .await?;
836
825
  } else if let Some(dims) = opts.dimensions {
837
826
  state
838
- .renderer()
827
+ .renderer
839
828
  .resize_with_dimensions(dims.width, dims.height)
840
829
  .await?;
841
830
  } else {
842
- state.renderer().resize().await?;
831
+ state.renderer.resize().await?;
843
832
  }
844
833
 
845
834
  Ok(())
@@ -914,9 +903,13 @@ impl PerspectiveViewerElement {
914
903
  } else {
915
904
  *self.intersection_handle.borrow_mut() = None;
916
905
  if self.session.set_pause(false) {
917
- return ApiFuture::new(
918
- self.restore_and_render(ViewerConfigUpdate::default(), async move { Ok(()) }),
919
- );
906
+ return ApiFuture::new(restore_and_render(
907
+ &self.session,
908
+ &self.renderer,
909
+ &self.presentation,
910
+ ViewerConfigUpdate::default(),
911
+ async move { Ok(()) },
912
+ ));
920
913
  }
921
914
  }
922
915
 
@@ -934,10 +927,6 @@ impl PerspectiveViewerElement {
934
927
  #[wasm_bindgen]
935
928
  pub fn setSelection(&self, window: Option<JsViewWindow>) -> ApiResult<()> {
936
929
  let window = window.map(|x| x.into_serde_ext()).transpose()?;
937
- if self.renderer.get_selection() != window {
938
- self.custom_events.dispatch_select(window.as_ref())?;
939
- }
940
-
941
930
  self.renderer.set_selection(window);
942
931
  Ok(())
943
932
  }
@@ -1108,7 +1097,7 @@ impl PerspectiveViewerElement {
1108
1097
  pub fn toggleColumnSettings(&self, column_name: String) -> ApiFuture<()> {
1109
1098
  clone!(self.session, self.root);
1110
1099
  ApiFuture::new_throttled(async move {
1111
- let locator = session.get_column_locator(Some(column_name));
1100
+ let locator = get_column_locator(&session.metadata(), Some(column_name));
1112
1101
  let (sender, receiver) = channel::<()>();
1113
1102
  root.borrow().as_ref().into_apierror()?.send_message(
1114
1103
  PerspectiveViewerMsg::OpenColumnSettings {
@@ -1130,7 +1119,7 @@ impl PerspectiveViewerElement {
1130
1119
  column_name: Option<String>,
1131
1120
  toggle: Option<bool>,
1132
1121
  ) -> ApiFuture<()> {
1133
- let locator = self.get_column_locator(column_name);
1122
+ let locator = get_column_locator(&self.session.metadata(), column_name);
1134
1123
  clone!(self.root);
1135
1124
  ApiFuture::new_throttled(async move {
1136
1125
  let (sender, receiver) = channel::<()>();