@perspective-dev/viewer 4.5.1 → 5.0.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 (212) hide show
  1. package/dist/cdn/perspective-viewer.js +20 -1
  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/monokai.css +1 -1
  9. package/dist/css/phosphor.css +1 -1
  10. package/dist/css/pro-dark.css +1 -1
  11. package/dist/css/pro.css +1 -1
  12. package/dist/css/solarized-dark.css +1 -1
  13. package/dist/css/solarized.css +1 -1
  14. package/dist/css/themes.css +1 -1
  15. package/dist/css/vaporwave.css +1 -1
  16. package/dist/esm/extensions.d.ts +22 -3
  17. package/dist/esm/perspective-viewer.cdn.d.ts +3 -0
  18. package/dist/esm/perspective-viewer.d.ts +9 -0
  19. package/dist/esm/perspective-viewer.inline.d.ts +3 -0
  20. package/dist/esm/perspective-viewer.inline.js +20 -1
  21. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  22. package/dist/esm/perspective-viewer.js +20 -1
  23. package/dist/esm/perspective-viewer.js.map +4 -4
  24. package/dist/esm/plugin.d.ts +71 -5
  25. package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
  26. package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
  27. package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
  28. package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
  29. package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
  30. package/dist/esm/ts-rs/Layout.d.ts +11 -0
  31. package/dist/esm/ts-rs/OnUpdateData.d.ts +6 -0
  32. package/dist/esm/ts-rs/Orientation.d.ts +4 -0
  33. package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
  34. package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
  35. package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
  36. package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
  37. package/dist/esm/ts-rs/ViewOnUpdateResp.d.ts +4 -0
  38. package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
  39. package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
  40. package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
  41. package/dist/wasm/perspective-viewer.d.ts +213 -79
  42. package/dist/wasm/perspective-viewer.js +537 -189
  43. package/dist/wasm/perspective-viewer.wasm +0 -0
  44. package/dist/wasm/perspective-viewer.wasm.d.ts +36 -28
  45. package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
  46. package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
  47. package/package.json +3 -2
  48. package/src/css/_column_dropdown.css +14 -0
  49. package/src/css/_context_menu.css +14 -0
  50. package/src/css/_dropdown_menu.css +14 -0
  51. package/src/css/_filter_dropdown.css +14 -0
  52. package/src/css/_function_dropdown.css +14 -0
  53. package/src/css/_viewer_bundle.css +41 -0
  54. package/src/css/column-settings-panel.css +1 -1
  55. package/src/css/containers/context-menu.css +101 -0
  56. package/src/css/panel-tab.css +193 -0
  57. package/src/css/plugin-selector.css +7 -10
  58. package/src/css/status-bar.css +75 -81
  59. package/src/css/viewer.css +181 -71
  60. package/src/rust/components/column_dropdown.rs +43 -33
  61. package/src/rust/components/column_selector/active_column.rs +7 -18
  62. package/src/rust/components/column_selector/aggregate_selector.rs +4 -10
  63. package/src/rust/components/column_selector/config_selector.rs +33 -84
  64. package/src/rust/components/column_selector/empty_column.rs +0 -3
  65. package/src/rust/components/column_selector/filter_column.rs +5 -18
  66. package/src/rust/components/column_selector/inactive_column.rs +3 -8
  67. package/src/rust/components/column_selector/invalid_column.rs +0 -4
  68. package/src/rust/components/column_selector/sort_column.rs +3 -6
  69. package/src/rust/components/column_selector.rs +5 -14
  70. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +0 -3
  71. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +0 -3
  72. package/src/rust/components/column_settings_sidebar.rs +0 -3
  73. package/src/rust/components/containers/dropdown_menu.rs +1 -3
  74. package/src/rust/components/containers/scroll_panel.rs +1 -3
  75. package/src/rust/components/containers/split_panel.rs +175 -66
  76. package/src/rust/components/containers/tab_list.rs +0 -3
  77. package/src/rust/components/context_menu.rs +130 -0
  78. package/src/rust/components/datetime_column_style.rs +0 -3
  79. package/src/rust/components/empty_row.rs +0 -3
  80. package/src/rust/components/expression_editor.rs +2 -3
  81. package/src/rust/components/filter_dropdown.rs +3 -3
  82. package/src/rust/components/font_loader.rs +2 -2
  83. package/src/rust/components/form/code_editor.rs +0 -3
  84. package/src/rust/components/form/debug.rs +3 -4
  85. package/src/rust/components/function_dropdown.rs +3 -3
  86. package/src/rust/components/global_filter_bar.rs +76 -0
  87. package/src/rust/components/main_panel/frame_theme.rs +186 -0
  88. package/src/rust/components/main_panel/msg.rs +62 -0
  89. package/src/rust/components/main_panel/presize.rs +220 -0
  90. package/src/rust/components/main_panel/reconcile.rs +224 -0
  91. package/src/rust/components/main_panel/render.rs +385 -0
  92. package/src/rust/components/main_panel/update.rs +184 -0
  93. package/src/rust/components/main_panel.rs +311 -71
  94. package/src/rust/components/mod.rs +4 -0
  95. package/src/rust/components/number_series_style.rs +0 -3
  96. package/src/rust/components/panel_menu.rs +486 -0
  97. package/src/rust/components/panel_tab.rs +505 -0
  98. package/src/rust/components/plugin_selector.rs +0 -3
  99. package/src/rust/components/plugin_tab.rs +1 -6
  100. package/src/rust/components/portal.rs +5 -2
  101. package/src/rust/components/render_warning.rs +0 -3
  102. package/src/rust/components/settings_panel.rs +13 -5
  103. package/src/rust/components/status_bar.rs +113 -180
  104. package/src/rust/components/status_indicator.rs +6 -9
  105. package/src/rust/components/string_column_style.rs +0 -3
  106. package/src/rust/components/style/mod.rs +65 -27
  107. package/src/rust/components/style/style_provider.rs +51 -16
  108. package/src/rust/components/style_controls/number_string_format.rs +1 -8
  109. package/src/rust/components/type_icon.rs +1 -4
  110. package/src/rust/components/viewer/filters.rs +133 -0
  111. package/src/rust/components/viewer/msg.rs +180 -0
  112. package/src/rust/components/viewer/panels.rs +326 -0
  113. package/src/rust/components/viewer/render.rs +243 -0
  114. package/src/rust/components/viewer/settings.rs +402 -0
  115. package/src/rust/components/viewer/snapshots.rs +134 -0
  116. package/src/rust/components/viewer/wiring.rs +505 -0
  117. package/src/rust/components/viewer.rs +243 -758
  118. package/src/rust/config/export_method.rs +1 -1
  119. package/src/rust/config/mod.rs +4 -0
  120. package/src/rust/config/options.rs +71 -0
  121. package/src/rust/config/viewer_config.rs +24 -2
  122. package/src/rust/config/workspace_config.rs +92 -0
  123. package/src/rust/custom_elements/copy_dropdown.rs +9 -3
  124. package/src/rust/custom_elements/debug_plugin.rs +20 -1
  125. package/src/rust/custom_elements/export_dropdown.rs +9 -3
  126. package/src/rust/custom_elements/viewer.rs +1015 -286
  127. package/src/rust/custom_events.rs +212 -61
  128. package/src/rust/js/mod.rs +2 -0
  129. package/src/rust/js/plugin.rs +297 -10
  130. package/src/rust/js/regular_layout.rs +258 -0
  131. package/src/rust/lib.rs +20 -2
  132. package/src/rust/presentation.rs +66 -33
  133. package/src/rust/queries/get_viewer_config.rs +29 -11
  134. package/src/rust/queries/plugin_column_styles.rs +2 -2
  135. package/src/rust/renderer/activate.rs +41 -14
  136. package/src/rust/renderer/dispatch.rs +436 -0
  137. package/src/rust/renderer/plugin_config.rs +495 -0
  138. package/src/rust/renderer/registry.rs +18 -6
  139. package/src/rust/renderer/render_timer.rs +29 -10
  140. package/src/rust/renderer.rs +350 -827
  141. package/src/rust/session/column_defaults_update.rs +26 -8
  142. package/src/rust/session/metadata.rs +11 -1
  143. package/src/rust/session/view_subscription.rs +30 -15
  144. package/src/rust/session.rs +753 -251
  145. package/src/rust/tasks/apply_global_filters.rs +89 -0
  146. package/src/rust/tasks/auto_pause.rs +171 -0
  147. package/src/rust/tasks/copy_export.rs +29 -19
  148. package/src/rust/tasks/create_panel.rs +243 -0
  149. package/src/rust/tasks/dismiss_render_warning.rs +3 -1
  150. package/src/rust/tasks/edit_expression.rs +4 -4
  151. package/src/rust/tasks/eject.rs +64 -23
  152. package/src/rust/tasks/mod.rs +28 -4
  153. package/src/rust/tasks/pipeline.rs +411 -0
  154. package/src/rust/tasks/presize_panels.rs +324 -0
  155. package/src/rust/tasks/reset_all.rs +22 -12
  156. package/src/rust/tasks/resize_observer.rs +124 -87
  157. package/src/rust/tasks/restore_and_render.rs +80 -86
  158. package/src/rust/tasks/restore_panel.rs +145 -0
  159. package/src/rust/tasks/send_column_config.rs +5 -2
  160. package/src/rust/tasks/send_plugin_config.rs +5 -2
  161. package/src/rust/tasks/set_edit_mode.rs +59 -0
  162. package/src/rust/tasks/sync_update_panels.rs +152 -0
  163. package/src/rust/tasks/table_lifecycle.rs +158 -0
  164. package/src/rust/tasks/update_theme.rs +56 -12
  165. package/src/rust/utils/completion.rs +56 -0
  166. package/src/rust/utils/custom_element.rs +5 -0
  167. package/src/rust/utils/debounce.rs +130 -7
  168. package/src/rust/utils/mod.rs +6 -0
  169. package/src/rust/utils/pending_effects.rs +62 -0
  170. package/src/rust/{components/style/local_style.rs → utils/spawn.rs} +17 -19
  171. package/src/rust/utils/weak_scope.rs +0 -10
  172. package/src/rust/workspace.rs +846 -0
  173. package/src/svg/active-indicator.svg +3 -0
  174. package/src/themes/botanical.css +7 -2
  175. package/src/themes/defaults.css +54 -2
  176. package/src/themes/dracula.css +8 -3
  177. package/src/themes/gruvbox-dark.css +7 -2
  178. package/src/themes/gruvbox.css +5 -2
  179. package/src/themes/icons.css +4 -2
  180. package/src/themes/monokai.css +7 -2
  181. package/src/themes/phosphor.css +7 -2
  182. package/src/themes/pro-dark.css +7 -2
  183. package/src/themes/pro.css +2 -1
  184. package/src/themes/solarized-dark.css +5 -2
  185. package/src/themes/solarized.css +5 -2
  186. package/src/themes/vaporwave.css +7 -2
  187. package/src/ts/bootstrap.ts +8 -7
  188. package/src/ts/extensions.ts +30 -2
  189. package/src/ts/perspective-viewer.ts +10 -0
  190. package/src/ts/plugin.ts +72 -5
  191. package/src/ts/ts-rs/ClientOptions.ts +7 -0
  192. package/src/ts/ts-rs/ExportMethod.ts +3 -0
  193. package/src/ts/ts-rs/ExportOptions.ts +8 -0
  194. package/src/ts/ts-rs/GetClientOptions.ts +7 -0
  195. package/src/ts/ts-rs/GetTableOptions.ts +7 -0
  196. package/src/ts/ts-rs/Layout.ts +9 -0
  197. package/src/ts/ts-rs/Orientation.ts +6 -0
  198. package/src/ts/ts-rs/PanelOptions.ts +7 -0
  199. package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
  200. package/src/ts/ts-rs/SplitLayout.ts +5 -0
  201. package/src/ts/ts-rs/TabLayout.ts +11 -0
  202. package/src/ts/ts-rs/ViewerConfig.ts +6 -2
  203. package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
  204. package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
  205. package/tsconfig.json +1 -1
  206. package/src/rust/components/style/style_cache.rs +0 -136
  207. package/src/rust/tasks/intersection_observer.rs +0 -98
  208. package/src/rust/tasks/update_and_render.rs +0 -110
  209. /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
  210. /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
  211. /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
  212. /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline4.js → perspective-viewer-daeef4ceb066e6c7/inline5.js} +0 -0
@@ -17,7 +17,7 @@ use yew::prelude::*;
17
17
 
18
18
  use crate::js::*;
19
19
 
20
- #[derive(Clone, Copy, Eq, PartialEq, Deserialize)]
20
+ #[derive(Clone, Copy, Eq, PartialEq, Deserialize, ts_rs::TS)]
21
21
  pub enum ExportMethod {
22
22
  #[serde(rename = "csv")]
23
23
  Csv,
@@ -20,10 +20,12 @@ mod export_method;
20
20
  mod kvpair;
21
21
  mod number_series_style;
22
22
  mod number_string_format;
23
+ mod options;
23
24
  mod plugin_static_config;
24
25
  mod string_column_style;
25
26
  pub mod view_config;
26
27
  mod viewer_config;
28
+ mod workspace_config;
27
29
 
28
30
  pub use column_config_schema::*;
29
31
  pub use columns_config::*;
@@ -31,7 +33,9 @@ pub use datetime_column_style::*;
31
33
  pub use export_method::*;
32
34
  pub use number_series_style::*;
33
35
  pub use number_string_format::*;
36
+ pub use options::*;
34
37
  pub use plugin_static_config::*;
35
38
  pub use string_column_style::*;
36
39
  pub use view_config::*;
37
40
  pub use viewer_config::*;
41
+ pub use workspace_config::*;
@@ -0,0 +1,71 @@
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
+ //! Argument dictionaries for the public `PerspectiveViewerElement` methods.
14
+ //! Each derives `ts_rs::TS` so its TypeScript type is generated (and
15
+ //! re-exported from the crate's `typescript_custom_section`) alongside the
16
+ //! config types, rather than hand-maintained.
17
+
18
+ use serde::Deserialize;
19
+ use ts_rs::TS;
20
+
21
+ use crate::config::ExportMethod;
22
+
23
+ /// Selects the target panel of a panel-scoped `<perspective-viewer>` method;
24
+ /// the active panel when `panel` is omitted.
25
+ #[derive(Deserialize, Default, TS)]
26
+ pub struct PanelOptions {
27
+ #[ts(optional)]
28
+ pub panel: Option<String>,
29
+ }
30
+
31
+ /// The `eject` argument: the loaded client to remove by name; the active
32
+ /// panel's client when omitted.
33
+ #[derive(Deserialize, Default, TS)]
34
+ pub struct ClientOptions {
35
+ #[ts(optional)]
36
+ pub client: Option<String>,
37
+ }
38
+
39
+ /// The `download` / `export` / `copy` argument: the `ExportMethod` and target
40
+ /// panel.
41
+ #[derive(Deserialize, Default, TS)]
42
+ pub struct ExportOptions {
43
+ #[ts(as = "Option<ExportMethod>")]
44
+ #[ts(optional)]
45
+ pub method: Option<String>,
46
+
47
+ #[ts(optional)]
48
+ pub panel: Option<String>,
49
+ }
50
+
51
+ /// The `getTable` argument: whether to `wait` for a `Table`, and the target
52
+ /// panel.
53
+ #[derive(Deserialize, Default, TS)]
54
+ pub struct GetTableOptions {
55
+ #[ts(optional)]
56
+ pub wait: Option<bool>,
57
+
58
+ #[ts(optional)]
59
+ pub panel: Option<String>,
60
+ }
61
+
62
+ /// The `getClient` argument: whether to `wait` for a `Client`, and the target
63
+ /// panel.
64
+ #[derive(Deserialize, Default, TS)]
65
+ pub struct GetClientOptions {
66
+ #[ts(optional)]
67
+ pub wait: Option<bool>,
68
+
69
+ #[ts(optional)]
70
+ pub panel: Option<String>,
71
+ }
@@ -23,15 +23,29 @@ use wasm_bindgen::prelude::*;
23
23
  use crate::renderer::ColumnConfigMap;
24
24
 
25
25
  /// The state of an entire `custom_elements::PerspectiveViewerElement` component
26
- /// and its `Plugin`.
26
+ /// and its `Plugin`: the element-level `settings` flag plus the per-panel
27
+ /// [`PanelViewerConfig`]. The split exists so the whole-element config format
28
+ /// can serialize panel entries *without* a `settings` key (it is element-level
29
+ /// state there, carried by the top-level `active` field instead), while the
30
+ /// single-panel format flattens back to the legacy shape.
27
31
  #[derive(Debug, Default, Serialize, PartialEq, TS)]
28
32
  #[serde(deny_unknown_fields)]
29
33
  pub struct ViewerConfig<V: TS = String> {
34
+ pub settings: bool,
35
+
36
+ #[serde(flatten)]
37
+ pub panel: PanelViewerConfig<V>,
38
+ }
39
+
40
+ /// The per-panel state of a [`ViewerConfig`] — everything except the
41
+ /// element-level `settings` flag. This is the `panels` entry type of the
42
+ /// whole-element config format.
43
+ #[derive(Debug, Default, Serialize, PartialEq, TS)]
44
+ pub struct PanelViewerConfig<V: TS = String> {
30
45
  pub version: V,
31
46
  pub columns_config: ColumnConfigMap,
32
47
  pub plugin: String,
33
48
  pub plugin_config: serde_json::Map<String, Value>,
34
- pub settings: bool,
35
49
  pub table: Option<String>,
36
50
  pub theme: Option<String>,
37
51
  pub title: Option<String>,
@@ -40,6 +54,14 @@ pub struct ViewerConfig<V: TS = String> {
40
54
  pub view_config: ViewConfig,
41
55
  }
42
56
 
57
+ impl<V: TS> Deref for ViewerConfig<V> {
58
+ type Target = PanelViewerConfig<V>;
59
+
60
+ fn deref(&self) -> &Self::Target {
61
+ &self.panel
62
+ }
63
+ }
64
+
43
65
  pub static API_VERSION: LazyLock<&'static str> = LazyLock::new(|| {
44
66
  #[derive(Deserialize)]
45
67
  struct Package {
@@ -0,0 +1,92 @@
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 std::collections::BTreeMap;
14
+
15
+ use perspective_client::config::Filter;
16
+
17
+ use crate::config::{PanelViewerConfig, ViewerConfigUpdate};
18
+
19
+ /// The whole-element config format (`{version, active?, layout, panels}`) —
20
+ /// the multi-panel counterpart of the single-panel [`ViewerConfig`] — as
21
+ /// emitted by [`PerspectiveViewerElement::save`].
22
+ ///
23
+ /// - `panels` entries are [`PanelViewerConfig`]s: per-panel state only, no
24
+ /// `settings` key (element-level state).
25
+ /// - `active` names the panel targeted by the *open* settings sidebar; it is
26
+ /// omitted when the sidebar is closed.
27
+ #[derive(serde::Serialize, ts_rs::TS)]
28
+ pub struct WorkspaceConfig {
29
+ pub version: String,
30
+
31
+ #[serde(skip_serializing_if = "Option::is_none")]
32
+ #[ts(optional)]
33
+ pub active: Option<String>,
34
+
35
+ pub layout: Option<crate::js::Layout>,
36
+
37
+ /// `BTreeMap` (not `HashMap`) so `save()` serializes panels in a
38
+ /// DETERMINISTIC (sorted) key order — a fresh `HashMap` per call
39
+ /// iterates in a per-instance random order, which made consecutive
40
+ /// `save()` outputs byte-unstable.
41
+ pub panels: BTreeMap<String, PanelViewerConfig>,
42
+
43
+ /// The element-level global (master/detail cross-) filters. A transient
44
+ /// overlay on every detail panel's view — persisted here, never in a
45
+ /// per-panel entry. Omitted when empty.
46
+ #[serde(skip_serializing_if = "Vec::is_empty")]
47
+ #[ts(as = "Option<_>")]
48
+ #[ts(optional)]
49
+ pub global_filters: Vec<Filter>,
50
+
51
+ /// The MASTER (filter-source) panels' ids, referencing `panels` keys.
52
+ /// Roles are layout state (like the panel arrangement), so they persist;
53
+ /// which master contributed which clause does not — restored
54
+ /// `global_filters` are one unattributed bucket. Omitted when empty.
55
+ #[serde(skip_serializing_if = "Vec::is_empty")]
56
+ #[ts(as = "Option<_>")]
57
+ #[ts(optional)]
58
+ pub masters: Vec<String>,
59
+ }
60
+
61
+ /// The parse target of a whole-element config in
62
+ /// [`PerspectiveViewerElement::restore`]. Mirrors [`WorkspaceConfig`],
63
+ /// but `panels` entries are full [`ViewerConfigUpdate`]s so a stray per-panel
64
+ /// `settings` can be detected (warned, then ignored — `create_panel` strips
65
+ /// it).
66
+ #[derive(serde::Deserialize, ts_rs::TS)]
67
+ pub struct WorkspaceConfigUpdate {
68
+ #[serde(default)]
69
+ #[ts(optional)]
70
+ pub active: Option<String>,
71
+
72
+ #[serde(default)]
73
+ #[ts(optional)]
74
+ pub layout: Option<crate::js::Layout>,
75
+
76
+ pub panels: BTreeMap<String, ViewerConfigUpdate>,
77
+
78
+ /// The element-level global (master/detail cross-) filters to re-apply as
79
+ /// a transient overlay on every DETAIL panel. Restored as one
80
+ /// unattributed bucket: the next selection on any master replaces it.
81
+ #[serde(default)]
82
+ #[ts(as = "Option<_>")]
83
+ #[ts(optional)]
84
+ pub global_filters: Vec<Filter>,
85
+
86
+ /// The master (filter-source) panels, by saved `panels` key. An id not in
87
+ /// `panels` warns and is dropped.
88
+ #[serde(default)]
89
+ #[ts(as = "Option<_>")]
90
+ #[ts(optional)]
91
+ pub masters: Vec<String>,
92
+ }
@@ -22,7 +22,7 @@ use yew::prelude::*;
22
22
  use super::viewer::PerspectiveViewerElement;
23
23
  use crate::components::copy_dropdown::CopyDropDownMenu;
24
24
  use crate::components::portal::PortalModal;
25
- use crate::components::style::StyleProvider;
25
+ use crate::components::style::{StyleProvider, StyleSurface};
26
26
  use crate::config::*;
27
27
  use crate::js::*;
28
28
  use crate::presentation::Presentation;
@@ -77,9 +77,13 @@ impl Component for CopyDropDownWrapper {
77
77
  fn view(&self, ctx: &Context<Self>) -> Html {
78
78
  let on_close = ctx.link().callback(|_| CopyDropDownWrapperMsg::Close);
79
79
  html! {
80
- <StyleProvider root={ctx.props().custom_element.clone()}>
80
+ <StyleProvider
81
+ root={ctx.props().custom_element.clone()}
82
+ surface={StyleSurface::DropdownMenu}
83
+ >
81
84
  <PortalModal
82
85
  tag_name="perspective-copy-menu"
86
+ surface={StyleSurface::DropdownMenu}
83
87
  target={self.target.clone()}
84
88
  own_focus=true
85
89
  {on_close}
@@ -133,7 +137,9 @@ impl CopyDropDownMenuElement {
133
137
  }
134
138
 
135
139
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
136
- self.set_config_model(&parent.session, &parent.renderer, &parent.presentation)
140
+ if let Some(panel) = parent.workspace.active_panel() {
141
+ self.set_config_model(&panel.session, &panel.renderer, &parent.presentation);
142
+ }
137
143
  }
138
144
 
139
145
  pub fn connected_callback(&self) {}
@@ -65,8 +65,27 @@ impl PerspectiveDebugPluginElement {
65
65
  JsValue::UNDEFINED
66
66
  }
67
67
 
68
+ /// Delegates to `draw()` VIRTUALLY — through the JS element's `draw`
69
+ /// property, never `self.draw(view)` (Rust static dispatch). This
70
+ /// element is the documented base class for custom plugins
71
+ /// (`class MyPlugin extends
72
+ /// customElements.get("perspective-viewer-plugin")`), whose contract is
73
+ /// "`update()` defaults to dispatch to `draw()`" — a
74
+ /// subclass overriding only `draw` must receive `update`-path repaints
75
+ /// (`BindDisposition::Unchanged`/`Adopted` runs,
76
+ /// `PLUGIN_DRAW_INVARIANT_PLAN.md`); the static call bypassed the
77
+ /// override and repainted the Debug CSV instead (the
78
+ /// `view_lifecycle.spec` regression).
68
79
  pub fn update(&self, view: &perspective_js::View) -> ApiFuture<()> {
69
- self.draw(view)
80
+ clone!(self.elem, view);
81
+ ApiFuture::new(async move {
82
+ let draw = js_sys::Reflect::get(&elem, &JsValue::from_str("draw"))?
83
+ .dyn_into::<js_sys::Function>()?;
84
+
85
+ let task = draw.call1(&elem, &JsValue::from(view))?;
86
+ wasm_bindgen_futures::JsFuture::from(js_sys::Promise::resolve(&task)).await?;
87
+ Ok(())
88
+ })
70
89
  }
71
90
 
72
91
  /// # Notes
@@ -22,7 +22,7 @@ use yew::prelude::*;
22
22
  use super::viewer::PerspectiveViewerElement;
23
23
  use crate::components::export_dropdown::ExportDropDownMenu;
24
24
  use crate::components::portal::PortalModal;
25
- use crate::components::style::StyleProvider;
25
+ use crate::components::style::{StyleProvider, StyleSurface};
26
26
  use crate::config::*;
27
27
  use crate::presentation::Presentation;
28
28
  use crate::renderer::*;
@@ -77,9 +77,13 @@ impl Component for ExportDropDownWrapper {
77
77
  fn view(&self, ctx: &Context<Self>) -> Html {
78
78
  let on_close = ctx.link().callback(|_| ExportDropDownWrapperMsg::Close);
79
79
  html! {
80
- <StyleProvider root={ctx.props().custom_element.clone()}>
80
+ <StyleProvider
81
+ root={ctx.props().custom_element.clone()}
82
+ surface={StyleSurface::DropdownMenu}
83
+ >
81
84
  <PortalModal
82
85
  tag_name="perspective-export-menu"
86
+ surface={StyleSurface::DropdownMenu}
83
87
  target={self.target.clone()}
84
88
  own_focus=true
85
89
  {on_close}
@@ -134,7 +138,9 @@ impl ExportDropDownMenuElement {
134
138
  }
135
139
 
136
140
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
137
- self.set_config_model(&parent.session, &parent.renderer, &parent.presentation)
141
+ if let Some(panel) = parent.workspace.active_panel() {
142
+ self.set_config_model(&panel.session, &panel.renderer, &parent.presentation);
143
+ }
138
144
  }
139
145
 
140
146
  pub fn connected_callback(&self) {}