@perspective-dev/viewer 4.5.2 → 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 (178) 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.d.ts +9 -0
  18. package/dist/esm/perspective-viewer.inline.js +20 -1
  19. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  20. package/dist/esm/perspective-viewer.js +20 -1
  21. package/dist/esm/perspective-viewer.js.map +4 -4
  22. package/dist/esm/plugin.d.ts +71 -5
  23. package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
  24. package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
  25. package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
  26. package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
  27. package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
  28. package/dist/esm/ts-rs/Layout.d.ts +11 -0
  29. package/dist/esm/ts-rs/Orientation.d.ts +4 -0
  30. package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
  31. package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
  32. package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
  33. package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
  34. package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
  35. package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
  36. package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
  37. package/dist/wasm/perspective-viewer.d.ts +211 -77
  38. package/dist/wasm/perspective-viewer.js +528 -180
  39. package/dist/wasm/perspective-viewer.wasm +0 -0
  40. package/dist/wasm/perspective-viewer.wasm.d.ts +34 -26
  41. package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
  42. package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
  43. package/package.json +3 -2
  44. package/src/css/_context_menu.css +14 -0
  45. package/src/css/column-settings-panel.css +1 -1
  46. package/src/css/containers/context-menu.css +101 -0
  47. package/src/css/panel-tab.css +193 -0
  48. package/src/css/plugin-selector.css +7 -10
  49. package/src/css/status-bar.css +75 -81
  50. package/src/css/viewer.css +180 -70
  51. package/src/rust/components/column_dropdown.rs +40 -30
  52. package/src/rust/components/column_selector/active_column.rs +7 -18
  53. package/src/rust/components/column_selector/aggregate_selector.rs +4 -7
  54. package/src/rust/components/column_selector/config_selector.rs +33 -81
  55. package/src/rust/components/column_selector/filter_column.rs +5 -15
  56. package/src/rust/components/column_selector/inactive_column.rs +3 -8
  57. package/src/rust/components/column_selector/sort_column.rs +3 -6
  58. package/src/rust/components/column_selector.rs +5 -11
  59. package/src/rust/components/containers/split_panel.rs +175 -62
  60. package/src/rust/components/context_menu.rs +130 -0
  61. package/src/rust/components/form/debug.rs +3 -0
  62. package/src/rust/components/global_filter_bar.rs +76 -0
  63. package/src/rust/components/main_panel/frame_theme.rs +186 -0
  64. package/src/rust/components/main_panel/msg.rs +62 -0
  65. package/src/rust/components/main_panel/presize.rs +220 -0
  66. package/src/rust/components/main_panel/reconcile.rs +224 -0
  67. package/src/rust/components/main_panel/render.rs +385 -0
  68. package/src/rust/components/main_panel/update.rs +184 -0
  69. package/src/rust/components/main_panel.rs +311 -71
  70. package/src/rust/components/mod.rs +4 -0
  71. package/src/rust/components/panel_menu.rs +486 -0
  72. package/src/rust/components/panel_tab.rs +505 -0
  73. package/src/rust/components/plugin_tab.rs +1 -1
  74. package/src/rust/components/settings_panel.rs +13 -5
  75. package/src/rust/components/status_bar.rs +110 -178
  76. package/src/rust/components/status_indicator.rs +6 -9
  77. package/src/rust/components/style/mod.rs +5 -0
  78. package/src/rust/components/style/style_provider.rs +2 -0
  79. package/src/rust/components/viewer/filters.rs +133 -0
  80. package/src/rust/components/viewer/msg.rs +180 -0
  81. package/src/rust/components/viewer/panels.rs +326 -0
  82. package/src/rust/components/viewer/render.rs +243 -0
  83. package/src/rust/components/viewer/settings.rs +402 -0
  84. package/src/rust/components/viewer/snapshots.rs +134 -0
  85. package/src/rust/components/viewer/wiring.rs +505 -0
  86. package/src/rust/components/viewer.rs +243 -756
  87. package/src/rust/config/export_method.rs +1 -1
  88. package/src/rust/config/mod.rs +4 -0
  89. package/src/rust/config/options.rs +71 -0
  90. package/src/rust/config/viewer_config.rs +24 -2
  91. package/src/rust/config/workspace_config.rs +92 -0
  92. package/src/rust/custom_elements/copy_dropdown.rs +3 -1
  93. package/src/rust/custom_elements/debug_plugin.rs +20 -1
  94. package/src/rust/custom_elements/export_dropdown.rs +3 -1
  95. package/src/rust/custom_elements/viewer.rs +1015 -286
  96. package/src/rust/custom_events.rs +212 -61
  97. package/src/rust/js/mod.rs +2 -0
  98. package/src/rust/js/plugin.rs +297 -10
  99. package/src/rust/js/regular_layout.rs +258 -0
  100. package/src/rust/lib.rs +20 -1
  101. package/src/rust/presentation.rs +66 -33
  102. package/src/rust/queries/get_viewer_config.rs +29 -11
  103. package/src/rust/queries/plugin_column_styles.rs +2 -2
  104. package/src/rust/renderer/activate.rs +41 -14
  105. package/src/rust/renderer/dispatch.rs +436 -0
  106. package/src/rust/renderer/plugin_config.rs +495 -0
  107. package/src/rust/renderer/registry.rs +18 -6
  108. package/src/rust/renderer/render_timer.rs +29 -10
  109. package/src/rust/renderer.rs +350 -837
  110. package/src/rust/session/column_defaults_update.rs +26 -8
  111. package/src/rust/session/view_subscription.rs +30 -15
  112. package/src/rust/session.rs +753 -264
  113. package/src/rust/tasks/apply_global_filters.rs +89 -0
  114. package/src/rust/tasks/auto_pause.rs +171 -0
  115. package/src/rust/tasks/copy_export.rs +29 -19
  116. package/src/rust/tasks/create_panel.rs +243 -0
  117. package/src/rust/tasks/dismiss_render_warning.rs +3 -1
  118. package/src/rust/tasks/edit_expression.rs +4 -4
  119. package/src/rust/tasks/eject.rs +64 -23
  120. package/src/rust/tasks/mod.rs +28 -4
  121. package/src/rust/tasks/pipeline.rs +411 -0
  122. package/src/rust/tasks/presize_panels.rs +324 -0
  123. package/src/rust/tasks/reset_all.rs +22 -12
  124. package/src/rust/tasks/resize_observer.rs +124 -87
  125. package/src/rust/tasks/restore_and_render.rs +80 -86
  126. package/src/rust/tasks/restore_panel.rs +145 -0
  127. package/src/rust/tasks/send_column_config.rs +5 -2
  128. package/src/rust/tasks/send_plugin_config.rs +5 -2
  129. package/src/rust/tasks/set_edit_mode.rs +59 -0
  130. package/src/rust/tasks/sync_update_panels.rs +152 -0
  131. package/src/rust/tasks/table_lifecycle.rs +158 -0
  132. package/src/rust/tasks/update_theme.rs +56 -12
  133. package/src/rust/utils/completion.rs +56 -0
  134. package/src/rust/utils/custom_element.rs +5 -0
  135. package/src/rust/utils/debounce.rs +130 -7
  136. package/src/rust/utils/mod.rs +6 -0
  137. package/src/rust/utils/pending_effects.rs +62 -0
  138. package/src/rust/utils/spawn.rs +33 -0
  139. package/src/rust/utils/weak_scope.rs +0 -10
  140. package/src/rust/workspace.rs +846 -0
  141. package/src/svg/active-indicator.svg +3 -0
  142. package/src/themes/botanical.css +5 -2
  143. package/src/themes/defaults.css +54 -2
  144. package/src/themes/dracula.css +6 -3
  145. package/src/themes/gruvbox-dark.css +5 -2
  146. package/src/themes/gruvbox.css +5 -2
  147. package/src/themes/icons.css +4 -2
  148. package/src/themes/monokai.css +5 -2
  149. package/src/themes/phosphor.css +5 -2
  150. package/src/themes/pro-dark.css +5 -2
  151. package/src/themes/pro.css +2 -1
  152. package/src/themes/solarized-dark.css +5 -2
  153. package/src/themes/solarized.css +5 -2
  154. package/src/themes/vaporwave.css +5 -2
  155. package/src/ts/bootstrap.ts +8 -7
  156. package/src/ts/extensions.ts +30 -2
  157. package/src/ts/perspective-viewer.ts +10 -0
  158. package/src/ts/plugin.ts +72 -5
  159. package/src/ts/ts-rs/ClientOptions.ts +7 -0
  160. package/src/ts/ts-rs/ExportMethod.ts +3 -0
  161. package/src/ts/ts-rs/ExportOptions.ts +8 -0
  162. package/src/ts/ts-rs/GetClientOptions.ts +7 -0
  163. package/src/ts/ts-rs/GetTableOptions.ts +7 -0
  164. package/src/ts/ts-rs/Layout.ts +9 -0
  165. package/src/ts/ts-rs/Orientation.ts +6 -0
  166. package/src/ts/ts-rs/PanelOptions.ts +7 -0
  167. package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
  168. package/src/ts/ts-rs/SplitLayout.ts +5 -0
  169. package/src/ts/ts-rs/TabLayout.ts +11 -0
  170. package/src/ts/ts-rs/ViewerConfig.ts +6 -2
  171. package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
  172. package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
  173. package/src/rust/tasks/intersection_observer.rs +0 -98
  174. package/src/rust/tasks/update_and_render.rs +0 -110
  175. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
  176. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
  177. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
  178. /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/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
+ }
@@ -137,7 +137,9 @@ impl CopyDropDownMenuElement {
137
137
  }
138
138
 
139
139
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
140
- 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
+ }
141
143
  }
142
144
 
143
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
@@ -138,7 +138,9 @@ impl ExportDropDownMenuElement {
138
138
  }
139
139
 
140
140
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
141
- 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
+ }
142
144
  }
143
145
 
144
146
  pub fn connected_callback(&self) {}