@perspective-dev/viewer 4.4.0 → 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 (228) 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 -0
  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 +6 -0
  26. package/dist/esm/perspective-viewer.d.ts +4 -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 +21 -77
  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 +39 -0
  36. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +7 -4
  37. package/dist/wasm/perspective-viewer.d.ts +88 -24
  38. package/dist/wasm/perspective-viewer.js +320 -151
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +22 -17
  41. package/package.json +24 -2
  42. package/src/css/column-selector.css +3 -2
  43. package/src/css/column-settings-panel.css +36 -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/status-bar.css +1 -1
  53. package/src/css/viewer.css +65 -3
  54. package/src/rust/components/column_dropdown.rs +3 -1
  55. package/src/rust/components/column_selector/active_column.rs +13 -19
  56. package/src/rust/components/column_selector/config_selector.rs +20 -20
  57. package/src/rust/components/column_selector/filter_column.rs +14 -14
  58. package/src/rust/components/column_selector/inactive_column.rs +9 -15
  59. package/src/rust/components/column_selector/pivot_column.rs +7 -7
  60. package/src/rust/components/column_selector/sort_column.rs +7 -7
  61. package/src/rust/components/column_selector.rs +55 -37
  62. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +15 -7
  63. package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +394 -0
  64. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +15 -6
  65. package/src/rust/components/column_settings_sidebar/style_tab.rs +267 -136
  66. package/src/rust/components/column_settings_sidebar.rs +43 -49
  67. package/src/rust/components/containers/dragdrop_list.rs +5 -5
  68. package/src/rust/components/containers/mod.rs +0 -1
  69. package/src/rust/components/containers/scroll_panel.rs +21 -7
  70. package/src/rust/components/containers/sidebar.rs +8 -6
  71. package/src/rust/components/containers/split_panel.rs +3 -3
  72. package/src/rust/components/containers/tab_list.rs +3 -9
  73. package/src/rust/components/copy_dropdown.rs +2 -3
  74. package/src/rust/components/datetime_column_style.rs +19 -81
  75. package/src/rust/components/editable_header.rs +2 -3
  76. package/src/rust/components/export_dropdown.rs +2 -3
  77. package/src/rust/components/expression_editor.rs +29 -17
  78. package/src/rust/components/filter_dropdown.rs +2 -1
  79. package/src/rust/components/form/color_range_selector.rs +14 -7
  80. package/src/rust/components/form/debug.rs +47 -37
  81. package/src/rust/components/main_panel.rs +24 -65
  82. package/src/rust/components/mod.rs +2 -1
  83. package/src/rust/components/number_series_style.rs +161 -0
  84. package/src/rust/components/plugin_tab.rs +221 -0
  85. package/src/rust/components/settings_panel.rs +181 -59
  86. package/src/rust/components/status_bar.rs +140 -173
  87. package/src/rust/components/status_indicator.rs +15 -22
  88. package/src/rust/components/string_column_style.rs +20 -82
  89. package/src/rust/components/style_controls/number_string_format.rs +14 -30
  90. package/src/rust/components/viewer.rs +92 -132
  91. package/src/rust/config/column_config_schema.rs +195 -0
  92. package/src/rust/config/columns_config.rs +4 -97
  93. package/src/rust/config/datetime_column_style.rs +0 -5
  94. package/src/rust/config/mod.rs +8 -2
  95. package/src/rust/config/number_series_style.rs +79 -0
  96. package/src/rust/config/plugin_static_config.rs +144 -0
  97. package/src/rust/config/string_column_style.rs +0 -5
  98. package/src/rust/config/viewer_config.rs +7 -8
  99. package/src/rust/custom_elements/copy_dropdown.rs +30 -18
  100. package/src/rust/custom_elements/debug_plugin.rs +5 -7
  101. package/src/rust/custom_elements/export_dropdown.rs +26 -18
  102. package/src/rust/custom_elements/viewer.rs +77 -77
  103. package/src/rust/custom_events.rs +181 -224
  104. package/src/rust/js/plugin.rs +45 -117
  105. package/src/rust/lib.rs +39 -5
  106. package/src/rust/presentation/drag_helpers.rs +206 -0
  107. package/src/rust/presentation/props.rs +8 -0
  108. package/src/rust/presentation.rs +256 -41
  109. package/src/rust/{tasks → queries}/column_locator.rs +17 -73
  110. package/src/rust/queries/column_values.rs +59 -0
  111. package/src/rust/{tasks → queries}/columns_iter_set.rs +11 -18
  112. package/src/rust/queries/exports.rs +96 -0
  113. package/src/rust/queries/fetch_column_stats.rs +94 -0
  114. package/src/rust/queries/get_viewer_config.rs +54 -0
  115. package/src/rust/queries/mod.rs +44 -0
  116. package/src/rust/queries/plugin_column_styles.rs +101 -0
  117. package/src/rust/{engines.rs → queries/validate_expression.rs} +26 -15
  118. package/src/rust/renderer/activate.rs +1 -0
  119. package/src/rust/renderer/limits.rs +9 -4
  120. package/src/rust/renderer/plugin_store.rs +12 -0
  121. package/src/rust/renderer/props.rs +28 -3
  122. package/src/rust/renderer/registry.rs +40 -15
  123. package/src/rust/renderer.rs +649 -55
  124. package/src/rust/session/column_defaults_update.rs +20 -28
  125. package/src/rust/session/drag_drop_update.rs +10 -10
  126. package/src/rust/session/metadata.rs +31 -16
  127. package/src/rust/session/props.rs +15 -6
  128. package/src/rust/session/view_subscription.rs +10 -0
  129. package/src/rust/session.rs +109 -147
  130. package/src/rust/tasks/copy_export.rs +178 -158
  131. package/src/rust/tasks/{structural.rs → dismiss_render_warning.rs} +20 -40
  132. package/src/rust/tasks/edit_expression.rs +68 -88
  133. package/src/rust/tasks/eject.rs +25 -22
  134. package/src/rust/tasks/intersection_observer.rs +8 -21
  135. package/src/rust/tasks/mod.rs +19 -21
  136. package/src/rust/tasks/reset_all.rs +78 -0
  137. package/src/rust/tasks/resize_observer.rs +11 -33
  138. package/src/rust/tasks/restore_and_render.rs +117 -89
  139. package/src/rust/tasks/{get_viewer_config.rs → send_column_config.rs} +38 -35
  140. package/src/rust/tasks/send_plugin_config.rs +32 -33
  141. package/src/rust/tasks/update_and_render.rs +66 -47
  142. package/src/rust/{components/containers/trap_door_panel.rs → tasks/update_theme.rs} +34 -33
  143. package/src/rust/tasks/validate_expression.rs +61 -0
  144. package/src/rust/utils/browser/selection.rs +4 -4
  145. package/src/rust/utils/mod.rs +0 -63
  146. package/src/svg/datagrid-select-row-tree.svg +13 -0
  147. package/src/svg/mega-menu-icons-density.svg +23 -0
  148. package/src/svg/mega-menu-icons-map-density.svg +24 -0
  149. package/src/svg/mega-menu-icons-map-line.svg +19 -0
  150. package/src/themes/botanical.css +27 -53
  151. package/src/themes/defaults.css +42 -36
  152. package/src/themes/dracula.css +36 -54
  153. package/src/themes/gruvbox-dark.css +39 -59
  154. package/src/themes/gruvbox.css +16 -28
  155. package/src/themes/icons.css +4 -18
  156. package/src/themes/intl/de.css +42 -6
  157. package/src/themes/intl/es.css +42 -6
  158. package/src/themes/intl/fr.css +42 -6
  159. package/src/themes/intl/ja.css +42 -6
  160. package/src/themes/intl/pt.css +42 -6
  161. package/src/themes/intl/zh.css +42 -6
  162. package/src/themes/intl.css +37 -4
  163. package/src/themes/monokai.css +45 -61
  164. package/src/themes/phosphor.css +175 -0
  165. package/src/themes/pro-dark.css +25 -34
  166. package/src/themes/solarized-dark.css +21 -36
  167. package/src/themes/solarized.css +13 -23
  168. package/src/themes/themes.css +1 -0
  169. package/src/themes/vaporwave.css +40 -74
  170. package/src/ts/bootstrap.ts +14 -3
  171. package/src/ts/column-format.ts +162 -0
  172. package/src/ts/extensions.ts +12 -1
  173. package/src/ts/perspective-viewer.ts +10 -1
  174. package/src/{rust/components/column_settings_sidebar/style_tab/stub.rs → ts/perspective-viewer.worker.ts} +2 -22
  175. package/src/ts/plugin.ts +29 -105
  176. package/src/ts/ts-rs/{FormatUnit.ts → ColumnSelectMode.ts} +1 -1
  177. package/src/ts/ts-rs/PluginStaticConfig.ts +78 -0
  178. package/src/ts/ts-rs/ViewerConfig.ts +14 -0
  179. package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -3
  180. package/dist/esm/ts-rs/ColumnConfigValues.d.ts +0 -31
  181. package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +0 -1
  182. package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +0 -15
  183. package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +0 -18
  184. package/dist/esm/ts-rs/DatetimeColorMode.d.ts +0 -1
  185. package/dist/esm/ts-rs/DatetimeFormatType.d.ts +0 -6
  186. package/dist/esm/ts-rs/FormatMode.d.ts +0 -1
  187. package/dist/esm/ts-rs/FormatUnit.d.ts +0 -1
  188. package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +0 -1
  189. package/dist/esm/ts-rs/NumberForegroundMode.d.ts +0 -1
  190. package/dist/esm/ts-rs/PluginConfig.d.ts +0 -2
  191. package/dist/esm/ts-rs/RoundingMode.d.ts +0 -1
  192. package/dist/esm/ts-rs/RoundingPriority.d.ts +0 -1
  193. package/dist/esm/ts-rs/SignDisplay.d.ts +0 -1
  194. package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +0 -1
  195. package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +0 -6
  196. package/dist/esm/ts-rs/StringColorMode.d.ts +0 -1
  197. package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +0 -1
  198. package/dist/esm/ts-rs/UseGrouping.d.ts +0 -1
  199. package/src/rust/components/number_column_style.rs +0 -483
  200. package/src/rust/config/number_column_style.rs +0 -132
  201. package/src/rust/dragdrop.rs +0 -481
  202. package/src/rust/tasks/plugin_column_styles.rs +0 -98
  203. package/src/ts/ts-rs/ColumnConfigValues.ts +0 -14
  204. package/src/ts/ts-rs/CustomDatetimeFormat.ts +0 -3
  205. package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +0 -5
  206. package/src/ts/ts-rs/CustomNumberFormatConfig.ts +0 -8
  207. package/src/ts/ts-rs/DatetimeColorMode.ts +0 -3
  208. package/src/ts/ts-rs/DatetimeFormatType.ts +0 -8
  209. package/src/ts/ts-rs/FormatMode.ts +0 -3
  210. package/src/ts/ts-rs/NumberBackgroundMode.ts +0 -3
  211. package/src/ts/ts-rs/NumberForegroundMode.ts +0 -3
  212. package/src/ts/ts-rs/PluginConfig.ts +0 -4
  213. package/src/ts/ts-rs/RoundingMode.ts +0 -3
  214. package/src/ts/ts-rs/RoundingPriority.ts +0 -3
  215. package/src/ts/ts-rs/SignDisplay.ts +0 -3
  216. package/src/ts/ts-rs/SimpleDatetimeFormat.ts +0 -3
  217. package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +0 -4
  218. package/src/ts/ts-rs/StringColorMode.ts +0 -3
  219. package/src/ts/ts-rs/TrailingZeroDisplay.ts +0 -3
  220. package/src/ts/ts-rs/UseGrouping.ts +0 -3
  221. /package/dist/wasm/snippets/{perspective-viewer-68fef752754ffbc6 → perspective-viewer-39ab7da3ca157861}/inline0.js +0 -0
  222. /package/dist/wasm/snippets/{perspective-viewer-68fef752754ffbc6 → perspective-viewer-39ab7da3ca157861}/inline1.js +0 -0
  223. /package/dist/wasm/snippets/{perspective-viewer-68fef752754ffbc6 → perspective-viewer-39ab7da3ca157861}/inline2.js +0 -0
  224. /package/dist/wasm/snippets/{perspective-viewer-68fef752754ffbc6 → perspective-viewer-39ab7da3ca157861}/inline3.js +0 -0
  225. /package/dist/wasm/snippets/{perspective-viewer-68fef752754ffbc6 → perspective-viewer-39ab7da3ca157861}/inline4.js +0 -0
  226. /package/src/rust/{tasks → config}/export_method.rs +0 -0
  227. /package/src/rust/{tasks → queries}/export_app.rs +0 -0
  228. /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,16 +93,14 @@ 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
- pub fn save(&self) -> ApiFuture<()> {
101
- ApiFuture::default()
98
+ pub fn save(&self) -> ApiResult<JsValue> {
99
+ Ok(JsValue::null())
102
100
  }
103
101
 
104
- pub fn restore(&self) -> ApiFuture<()> {
105
- ApiFuture::default()
102
+ pub fn restore(&self, _config: Option<JsValue>) -> ApiResult<()> {
103
+ Ok(())
106
104
  }
107
105
 
108
106
  pub fn delete(&self) -> ApiFuture<()> {
@@ -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};
@@ -39,6 +39,15 @@ use crate::tasks::*;
39
39
  use crate::utils::*;
40
40
  use crate::*;
41
41
 
42
+ #[wasm_bindgen]
43
+ extern "C" {
44
+ #[wasm_bindgen(typescript_type = "Promise<ViewerConfig>")]
45
+ pub type JsViewerConfigPromise;
46
+
47
+ #[wasm_bindgen(typescript_type = "ViewerConfigUpdate")]
48
+ pub type JsViewerConfigUpdate;
49
+ }
50
+
42
51
  #[derive(serde::Deserialize, Default)]
43
52
  struct ResizeOptions {
44
53
  dimensions: Option<ResizeDimensions>,
@@ -81,48 +90,17 @@ pub struct PerspectiveViewerElement {
81
90
  root: Root<components::viewer::PerspectiveViewer>,
82
91
  resize_handle: Rc<RefCell<Option<ResizeObserverHandle>>>,
83
92
  intersection_handle: Rc<RefCell<Option<IntersectionObserverHandle>>>,
84
- session: Session,
85
- renderer: Renderer,
86
- presentation: Presentation,
87
- custom_events: CustomEvents,
93
+ pub(crate) session: Session,
94
+ pub(crate) renderer: Renderer,
95
+ pub(crate) presentation: Presentation,
88
96
  _subscriptions: Rc<[Subscription; 2]>,
89
- }
90
-
91
- impl HasCustomEvents for PerspectiveViewerElement {
92
- fn custom_events(&self) -> &CustomEvents {
93
- &self.custom_events
94
- }
95
- }
96
-
97
- impl HasPresentation for PerspectiveViewerElement {
98
- fn presentation(&self) -> &Presentation {
99
- &self.presentation
100
- }
101
- }
102
-
103
- impl HasRenderer for PerspectiveViewerElement {
104
- fn renderer(&self) -> &Renderer {
105
- &self.renderer
106
- }
107
- }
108
-
109
- impl HasSession for PerspectiveViewerElement {
110
- fn session(&self) -> &Session {
111
- &self.session
112
- }
113
- }
114
-
115
- impl StateProvider for PerspectiveViewerElement {
116
- type State = PerspectiveViewerElement;
117
-
118
- fn clone_state(&self) -> Self::State {
119
- self.clone()
120
- }
97
+ _custom_event_subs: Rc<Vec<Subscription>>,
121
98
  }
122
99
 
123
100
  impl CustomElementMetadata for PerspectiveViewerElement {
124
101
  const CUSTOM_ELEMENT_NAME: &'static str = "perspective-viewer";
125
- const STATICS: &'static [&'static str] = ["registerPlugin"].as_slice();
102
+ const STATICS: &'static [&'static str] =
103
+ ["registerPlugin", "get_wasm_module", "get_worker_url"].as_slice();
126
104
  }
127
105
 
128
106
  #[wasm_bindgen]
@@ -144,7 +122,7 @@ impl PerspectiveViewerElement {
144
122
  let session = Session::new();
145
123
  let renderer = Renderer::new(&elem);
146
124
  let presentation = Presentation::new(&elem);
147
- let custom_events = CustomEvents::new(&elem, &session, &renderer, &presentation);
125
+ let custom_event_subs = wire_custom_events(&elem, &session, &renderer, &presentation);
148
126
 
149
127
  // Create Yew App
150
128
  let props = yew::props!(PerspectiveViewerProps {
@@ -152,11 +130,9 @@ impl PerspectiveViewerElement {
152
130
  session: session.clone(),
153
131
  renderer: renderer.clone(),
154
132
  presentation: presentation.clone(),
155
- dragdrop: DragDrop::new(&elem),
156
- custom_events: custom_events.clone(),
157
133
  });
158
134
 
159
- let state = props.clone_state();
135
+ let state = props.clone();
160
136
  let root = Root::new(shadow_root, props);
161
137
 
162
138
  // Create callbacks
@@ -176,7 +152,7 @@ impl PerspectiveViewerElement {
176
152
 
177
153
  let eject_sub = presentation.on_eject.add_listener({
178
154
  let root = root.clone();
179
- move |_| ApiFuture::spawn(state.delete_all(&root))
155
+ move |_| ApiFuture::spawn(delete_all(&state.session, &state.renderer, &root))
180
156
  });
181
157
 
182
158
  let resize_handle =
@@ -193,8 +169,8 @@ impl PerspectiveViewerElement {
193
169
  presentation,
194
170
  resize_handle: Rc::new(RefCell::new(Some(resize_handle))),
195
171
  intersection_handle: Rc::new(RefCell::new(Some(intersect_handle))),
196
- custom_events,
197
172
  _subscriptions: Rc::new([update_sub, eject_sub]),
173
+ _custom_event_subs: Rc::new(custom_event_subs),
198
174
  }
199
175
  }
200
176
 
@@ -361,7 +337,7 @@ impl PerspectiveViewerElement {
361
337
  /// await viewer.delete();
362
338
  /// ```
363
339
  pub fn delete(self) -> ApiFuture<()> {
364
- self.delete_all(&self.root)
340
+ delete_all(&self.session, &self.renderer, &self.root)
365
341
  }
366
342
 
367
343
  /// Restart this `<perspective-viewer>` to its initial state, before
@@ -414,12 +390,24 @@ impl PerspectiveViewerElement {
414
390
  /// [`PerspectiveViewerElement::save`]), and also makes no API calls to the
415
391
  /// server (unlike [`PerspectiveViewerElement::getView`] followed by
416
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).
417
400
  #[wasm_bindgen]
418
401
  pub fn getViewConfig(&self) -> ApiFuture<JsViewConfig> {
419
402
  let session = self.session.clone();
420
403
  ApiFuture::new(async move {
421
- let config = session.get_view_config();
422
- 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())
423
411
  })
424
412
  }
425
413
 
@@ -563,7 +551,7 @@ impl PerspectiveViewerElement {
563
551
  /// ```javascript
564
552
  /// await viewer.restore({group_by: ["State"]});
565
553
  /// ```
566
- pub fn restore(&self, update: JsValue) -> ApiFuture<()> {
554
+ pub fn restore(&self, update: JsViewerConfigUpdate) -> ApiFuture<()> {
567
555
  let this = self.clone();
568
556
  ApiFuture::new_throttled(async move {
569
557
  let decoded_update = ViewerConfigUpdate::decode(&update)?;
@@ -586,8 +574,12 @@ impl PerspectiveViewerElement {
586
574
  None
587
575
  };
588
576
 
589
- let result = this
590
- .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
+ {
591
583
  clone!(this, decoded_update.table);
592
584
  async move {
593
585
  if let OptionalUpdate::Update(name) = table {
@@ -605,11 +597,12 @@ impl PerspectiveViewerElement {
605
597
  receiver.await.unwrap_or_log();
606
598
  Ok(())
607
599
  }
608
- })
609
- .await;
600
+ },
601
+ )
602
+ .await;
610
603
 
611
604
  if let Err(e) = &result {
612
- this.session().set_error(false, e.clone()).await?;
605
+ this.session.set_error(false, e.clone()).await?;
613
606
  }
614
607
  result
615
608
  })
@@ -622,7 +615,7 @@ impl PerspectiveViewerElement {
622
615
  ApiFuture::spawn(self.session.reset(ResetOptions::default()));
623
616
  let this = self.clone();
624
617
  ApiFuture::new_throttled(async move {
625
- this.update_and_render(ViewConfigUpdate::default())?.await?;
618
+ update_and_render(&this.session, &this.renderer, ViewConfigUpdate::default())?.await?;
626
619
  Ok(())
627
620
  })
628
621
  }
@@ -646,17 +639,21 @@ impl PerspectiveViewerElement {
646
639
  /// await viewer.restore(token);
647
640
  /// });
648
641
  /// ```
649
- pub fn save(&self) -> ApiFuture<JsValue> {
642
+ pub fn save(&self) -> JsViewerConfigPromise {
650
643
  let this = self.clone();
651
- ApiFuture::new(async move {
644
+ let fut = ApiFuture::new(async move {
652
645
  let viewer_config = this
653
646
  .renderer
654
647
  .clone()
655
- .with_lock(async { this.get_viewer_config().await })
648
+ .with_lock(async {
649
+ get_viewer_config(&this.session, &this.renderer, &this.presentation).await
650
+ })
656
651
  .await?;
657
652
 
658
653
  viewer_config.encode()
659
- })
654
+ });
655
+
656
+ js_sys::Promise::from(fut).unchecked_into()
660
657
  }
661
658
 
662
659
  /// Download this viewer's internal [`View`] data via a browser download
@@ -685,7 +682,9 @@ impl PerspectiveViewerElement {
685
682
  ExportMethod::Csv
686
683
  };
687
684
 
688
- 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?;
689
688
  let is_chart = this.renderer.is_chart();
690
689
  download(
691
690
  format!("untitled{}", method.as_filename(is_chart)).as_ref(),
@@ -700,7 +699,7 @@ impl PerspectiveViewerElement {
700
699
  ///
701
700
  /// This method is only really useful for the `"plugin"` method, which
702
701
  /// will use the configured plugin's export (e.g. PNG for
703
- /// `@perspective-dev/viewer-d3fc`). Otherwise, prefer to call the
702
+ /// `@perspective-dev/viewer-charts`). Otherwise, prefer to call the
704
703
  /// equivalent method on the underlying [`View`] directly.
705
704
  ///
706
705
  /// # Arguments
@@ -724,7 +723,8 @@ impl PerspectiveViewerElement {
724
723
  ExportMethod::Csv
725
724
  };
726
725
 
727
- this.export_method_to_jsvalue(method).await
726
+ export_method_to_jsvalue(&this.session, &this.renderer, &this.presentation, method)
727
+ .await
728
728
  })
729
729
  }
730
730
 
@@ -755,7 +755,8 @@ impl PerspectiveViewerElement {
755
755
  ExportMethod::Csv
756
756
  };
757
757
 
758
- 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);
759
760
  copy_to_clipboard(js_task, MimeType::TextPlain).await
760
761
  })
761
762
  }
@@ -816,19 +817,18 @@ impl PerspectiveViewerElement {
816
817
  .unwrap_or_default()
817
818
  .unwrap_or_default();
818
819
 
819
- let state = self.clone_state();
820
+ let state = self.clone();
820
821
  ApiFuture::new_throttled(async move {
821
- if !state.renderer().is_plugin_activated()? {
822
- state
823
- .update_and_render(ViewConfigUpdate::default())?
822
+ if !state.renderer.is_plugin_activated()? {
823
+ update_and_render(&state.session, &state.renderer, ViewConfigUpdate::default())?
824
824
  .await?;
825
825
  } else if let Some(dims) = opts.dimensions {
826
826
  state
827
- .renderer()
827
+ .renderer
828
828
  .resize_with_dimensions(dims.width, dims.height)
829
829
  .await?;
830
830
  } else {
831
- state.renderer().resize().await?;
831
+ state.renderer.resize().await?;
832
832
  }
833
833
 
834
834
  Ok(())
@@ -903,9 +903,13 @@ impl PerspectiveViewerElement {
903
903
  } else {
904
904
  *self.intersection_handle.borrow_mut() = None;
905
905
  if self.session.set_pause(false) {
906
- return ApiFuture::new(
907
- self.restore_and_render(ViewerConfigUpdate::default(), async move { Ok(()) }),
908
- );
906
+ return ApiFuture::new(restore_and_render(
907
+ &self.session,
908
+ &self.renderer,
909
+ &self.presentation,
910
+ ViewerConfigUpdate::default(),
911
+ async move { Ok(()) },
912
+ ));
909
913
  }
910
914
  }
911
915
 
@@ -923,10 +927,6 @@ impl PerspectiveViewerElement {
923
927
  #[wasm_bindgen]
924
928
  pub fn setSelection(&self, window: Option<JsViewWindow>) -> ApiResult<()> {
925
929
  let window = window.map(|x| x.into_serde_ext()).transpose()?;
926
- if self.renderer.get_selection() != window {
927
- self.custom_events.dispatch_select(window.as_ref())?;
928
- }
929
-
930
930
  self.renderer.set_selection(window);
931
931
  Ok(())
932
932
  }
@@ -1097,7 +1097,7 @@ impl PerspectiveViewerElement {
1097
1097
  pub fn toggleColumnSettings(&self, column_name: String) -> ApiFuture<()> {
1098
1098
  clone!(self.session, self.root);
1099
1099
  ApiFuture::new_throttled(async move {
1100
- let locator = session.get_column_locator(Some(column_name));
1100
+ let locator = get_column_locator(&session.metadata(), Some(column_name));
1101
1101
  let (sender, receiver) = channel::<()>();
1102
1102
  root.borrow().as_ref().into_apierror()?.send_message(
1103
1103
  PerspectiveViewerMsg::OpenColumnSettings {
@@ -1119,7 +1119,7 @@ impl PerspectiveViewerElement {
1119
1119
  column_name: Option<String>,
1120
1120
  toggle: Option<bool>,
1121
1121
  ) -> ApiFuture<()> {
1122
- let locator = self.get_column_locator(column_name);
1122
+ let locator = get_column_locator(&self.session.metadata(), column_name);
1123
1123
  clone!(self.root);
1124
1124
  ApiFuture::new_throttled(async move {
1125
1125
  let (sender, receiver) = channel::<()>();