@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.
- package/dist/cdn/perspective-viewer.js +20 -1
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/gruvbox-dark.css +1 -1
- package/dist/css/gruvbox.css +1 -1
- package/dist/css/icons.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/phosphor.css +1 -1
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/css/solarized-dark.css +1 -1
- package/dist/css/solarized.css +1 -1
- package/dist/css/themes.css +1 -1
- package/dist/css/vaporwave.css +1 -1
- package/dist/esm/extensions.d.ts +22 -3
- package/dist/esm/perspective-viewer.d.ts +9 -0
- package/dist/esm/perspective-viewer.inline.js +20 -1
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +20 -1
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/plugin.d.ts +71 -5
- package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
- package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
- package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
- package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
- package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
- package/dist/esm/ts-rs/Layout.d.ts +11 -0
- package/dist/esm/ts-rs/Orientation.d.ts +4 -0
- package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
- package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
- package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
- package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
- package/dist/wasm/perspective-viewer.d.ts +211 -77
- package/dist/wasm/perspective-viewer.js +528 -180
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +34 -26
- package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
- package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
- package/package.json +3 -2
- package/src/css/_context_menu.css +14 -0
- package/src/css/column-settings-panel.css +1 -1
- package/src/css/containers/context-menu.css +101 -0
- package/src/css/panel-tab.css +193 -0
- package/src/css/plugin-selector.css +7 -10
- package/src/css/status-bar.css +75 -81
- package/src/css/viewer.css +180 -70
- package/src/rust/components/column_dropdown.rs +40 -30
- package/src/rust/components/column_selector/active_column.rs +7 -18
- package/src/rust/components/column_selector/aggregate_selector.rs +4 -7
- package/src/rust/components/column_selector/config_selector.rs +33 -81
- package/src/rust/components/column_selector/filter_column.rs +5 -15
- package/src/rust/components/column_selector/inactive_column.rs +3 -8
- package/src/rust/components/column_selector/sort_column.rs +3 -6
- package/src/rust/components/column_selector.rs +5 -11
- package/src/rust/components/containers/split_panel.rs +175 -62
- package/src/rust/components/context_menu.rs +130 -0
- package/src/rust/components/form/debug.rs +3 -0
- package/src/rust/components/global_filter_bar.rs +76 -0
- package/src/rust/components/main_panel/frame_theme.rs +186 -0
- package/src/rust/components/main_panel/msg.rs +62 -0
- package/src/rust/components/main_panel/presize.rs +220 -0
- package/src/rust/components/main_panel/reconcile.rs +224 -0
- package/src/rust/components/main_panel/render.rs +385 -0
- package/src/rust/components/main_panel/update.rs +184 -0
- package/src/rust/components/main_panel.rs +311 -71
- package/src/rust/components/mod.rs +4 -0
- package/src/rust/components/panel_menu.rs +486 -0
- package/src/rust/components/panel_tab.rs +505 -0
- package/src/rust/components/plugin_tab.rs +1 -1
- package/src/rust/components/settings_panel.rs +13 -5
- package/src/rust/components/status_bar.rs +110 -178
- package/src/rust/components/status_indicator.rs +6 -9
- package/src/rust/components/style/mod.rs +5 -0
- package/src/rust/components/style/style_provider.rs +2 -0
- package/src/rust/components/viewer/filters.rs +133 -0
- package/src/rust/components/viewer/msg.rs +180 -0
- package/src/rust/components/viewer/panels.rs +326 -0
- package/src/rust/components/viewer/render.rs +243 -0
- package/src/rust/components/viewer/settings.rs +402 -0
- package/src/rust/components/viewer/snapshots.rs +134 -0
- package/src/rust/components/viewer/wiring.rs +505 -0
- package/src/rust/components/viewer.rs +243 -756
- package/src/rust/config/export_method.rs +1 -1
- package/src/rust/config/mod.rs +4 -0
- package/src/rust/config/options.rs +71 -0
- package/src/rust/config/viewer_config.rs +24 -2
- package/src/rust/config/workspace_config.rs +92 -0
- package/src/rust/custom_elements/copy_dropdown.rs +3 -1
- package/src/rust/custom_elements/debug_plugin.rs +20 -1
- package/src/rust/custom_elements/export_dropdown.rs +3 -1
- package/src/rust/custom_elements/viewer.rs +1015 -286
- package/src/rust/custom_events.rs +212 -61
- package/src/rust/js/mod.rs +2 -0
- package/src/rust/js/plugin.rs +297 -10
- package/src/rust/js/regular_layout.rs +258 -0
- package/src/rust/lib.rs +20 -1
- package/src/rust/presentation.rs +66 -33
- package/src/rust/queries/get_viewer_config.rs +29 -11
- package/src/rust/queries/plugin_column_styles.rs +2 -2
- package/src/rust/renderer/activate.rs +41 -14
- package/src/rust/renderer/dispatch.rs +436 -0
- package/src/rust/renderer/plugin_config.rs +495 -0
- package/src/rust/renderer/registry.rs +18 -6
- package/src/rust/renderer/render_timer.rs +29 -10
- package/src/rust/renderer.rs +350 -837
- package/src/rust/session/column_defaults_update.rs +26 -8
- package/src/rust/session/view_subscription.rs +30 -15
- package/src/rust/session.rs +753 -264
- package/src/rust/tasks/apply_global_filters.rs +89 -0
- package/src/rust/tasks/auto_pause.rs +171 -0
- package/src/rust/tasks/copy_export.rs +29 -19
- package/src/rust/tasks/create_panel.rs +243 -0
- package/src/rust/tasks/dismiss_render_warning.rs +3 -1
- package/src/rust/tasks/edit_expression.rs +4 -4
- package/src/rust/tasks/eject.rs +64 -23
- package/src/rust/tasks/mod.rs +28 -4
- package/src/rust/tasks/pipeline.rs +411 -0
- package/src/rust/tasks/presize_panels.rs +324 -0
- package/src/rust/tasks/reset_all.rs +22 -12
- package/src/rust/tasks/resize_observer.rs +124 -87
- package/src/rust/tasks/restore_and_render.rs +80 -86
- package/src/rust/tasks/restore_panel.rs +145 -0
- package/src/rust/tasks/send_column_config.rs +5 -2
- package/src/rust/tasks/send_plugin_config.rs +5 -2
- package/src/rust/tasks/set_edit_mode.rs +59 -0
- package/src/rust/tasks/sync_update_panels.rs +152 -0
- package/src/rust/tasks/table_lifecycle.rs +158 -0
- package/src/rust/tasks/update_theme.rs +56 -12
- package/src/rust/utils/completion.rs +56 -0
- package/src/rust/utils/custom_element.rs +5 -0
- package/src/rust/utils/debounce.rs +130 -7
- package/src/rust/utils/mod.rs +6 -0
- package/src/rust/utils/pending_effects.rs +62 -0
- package/src/rust/utils/spawn.rs +33 -0
- package/src/rust/utils/weak_scope.rs +0 -10
- package/src/rust/workspace.rs +846 -0
- package/src/svg/active-indicator.svg +3 -0
- package/src/themes/botanical.css +5 -2
- package/src/themes/defaults.css +54 -2
- package/src/themes/dracula.css +6 -3
- package/src/themes/gruvbox-dark.css +5 -2
- package/src/themes/gruvbox.css +5 -2
- package/src/themes/icons.css +4 -2
- package/src/themes/monokai.css +5 -2
- package/src/themes/phosphor.css +5 -2
- package/src/themes/pro-dark.css +5 -2
- package/src/themes/pro.css +2 -1
- package/src/themes/solarized-dark.css +5 -2
- package/src/themes/solarized.css +5 -2
- package/src/themes/vaporwave.css +5 -2
- package/src/ts/bootstrap.ts +8 -7
- package/src/ts/extensions.ts +30 -2
- package/src/ts/perspective-viewer.ts +10 -0
- package/src/ts/plugin.ts +72 -5
- package/src/ts/ts-rs/ClientOptions.ts +7 -0
- package/src/ts/ts-rs/ExportMethod.ts +3 -0
- package/src/ts/ts-rs/ExportOptions.ts +8 -0
- package/src/ts/ts-rs/GetClientOptions.ts +7 -0
- package/src/ts/ts-rs/GetTableOptions.ts +7 -0
- package/src/ts/ts-rs/Layout.ts +9 -0
- package/src/ts/ts-rs/Orientation.ts +6 -0
- package/src/ts/ts-rs/PanelOptions.ts +7 -0
- package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
- package/src/ts/ts-rs/SplitLayout.ts +5 -0
- package/src/ts/ts-rs/TabLayout.ts +11 -0
- package/src/ts/ts-rs/ViewerConfig.ts +6 -2
- package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
- package/src/rust/tasks/intersection_observer.rs +0 -98
- package/src/rust/tasks/update_and_render.rs +0 -110
- /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-93064d0d79855d97/inline4.js → perspective-viewer-daeef4ceb066e6c7/inline5.js} +0 -0
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
//! Wire engine PubSub fanout to JavaScript `CustomEvent` dispatch
|
|
14
|
-
//!
|
|
15
|
-
//!
|
|
16
|
-
//! `
|
|
13
|
+
//! Wire engine PubSub fanout to JavaScript `CustomEvent` dispatch. Split into
|
|
14
|
+
//! [`wire_element_events`] (element-level, `Presentation`-driven, wired once)
|
|
15
|
+
//! and [`wire_panel_events`] (one panel's `Session`/`Renderer`, wired per
|
|
16
|
+
//! panel and owned by the `Panel`). Every `perspective-*` `CustomEvent`
|
|
17
|
+
//! originates from a PubSub fire; per-panel events dispatch on the originating
|
|
18
|
+
//! panel's plugin so `event.target` identifies the panel.
|
|
17
19
|
|
|
18
20
|
use perspective_client::{ViewWindow, clone};
|
|
19
21
|
use perspective_js::json;
|
|
@@ -27,6 +29,7 @@ use crate::queries::get_viewer_config;
|
|
|
27
29
|
use crate::renderer::{ColumnConfigMap, Renderer};
|
|
28
30
|
use crate::session::Session;
|
|
29
31
|
use crate::utils::{AddListener, Subscription};
|
|
32
|
+
use crate::workspace::Workspace;
|
|
30
33
|
|
|
31
34
|
/// Dispatch a JS `CustomEvent` named `perspective-{name}` on `elem`.
|
|
32
35
|
fn dispatch_event<T: Into<JsValue>>(elem: &HtmlElement, name: &str, event: T) -> ApiResult<()> {
|
|
@@ -41,7 +44,57 @@ fn dispatch_event<T: Into<JsValue>>(elem: &HtmlElement, name: &str, event: T) ->
|
|
|
41
44
|
Ok(())
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
/// The event target for a panel's events: the panel's own plugin element (so
|
|
48
|
+
/// `event.target`/`composedPath()` carries its `slot=<panel-id>`, identifying
|
|
49
|
+
/// the originating panel), falling back to the host when no plugin is drawn.
|
|
50
|
+
/// Events dispatched here bubble to the host, so element-level listeners still
|
|
51
|
+
/// fire.
|
|
52
|
+
fn panel_target(elem: &HtmlElement, renderer: &Renderer) -> EventTarget {
|
|
53
|
+
renderer
|
|
54
|
+
.active_plugin()
|
|
55
|
+
.filter(|plugin| elem.contains(Some(plugin.unchecked_ref::<web_sys::Node>())))
|
|
56
|
+
.map(|plugin| plugin.unchecked_into::<EventTarget>())
|
|
57
|
+
.unwrap_or_else(|| elem.clone().unchecked_into())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Dispatch a `perspective-{name}` `CustomEvent` for a single panel — on the
|
|
61
|
+
/// panel's plugin (see [`panel_target`]), bubbling + composed so it reaches the
|
|
62
|
+
/// host. The originating panel is identifiable from `event.target`; `detail`
|
|
63
|
+
/// shapes are otherwise unchanged from the single-panel case.
|
|
64
|
+
fn dispatch_panel_event(
|
|
65
|
+
elem: &HtmlElement,
|
|
66
|
+
renderer: &Renderer,
|
|
67
|
+
name: &str,
|
|
68
|
+
detail: &JsValue,
|
|
69
|
+
) -> ApiResult<()> {
|
|
70
|
+
let event_init = web_sys::CustomEventInit::new();
|
|
71
|
+
event_init.set_detail(detail);
|
|
72
|
+
event_init.set_bubbles(true);
|
|
73
|
+
event_init.set_composed(true);
|
|
74
|
+
let event = web_sys::CustomEvent::new_with_event_init_dict(
|
|
75
|
+
format!("perspective-{}", name).as_str(),
|
|
76
|
+
&event_init,
|
|
77
|
+
)?;
|
|
78
|
+
|
|
79
|
+
panel_target(elem, renderer).dispatch_event(&event)?;
|
|
80
|
+
Ok(())
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// Annotate an object `detail` with its originating panel id (`detail.panel`),
|
|
84
|
+
/// for the events whose detail is a plain JSON object (`select`,
|
|
85
|
+
/// `column-style-change`). Additive — existing single-panel listeners reading
|
|
86
|
+
/// the prior fields are unaffected; skipped when `detail` isn't an object (e.g.
|
|
87
|
+
/// a null selection) or the panel has no slot.
|
|
88
|
+
fn annotate_panel(detail: &JsValue, renderer: &Renderer) {
|
|
89
|
+
if detail.is_object()
|
|
90
|
+
&& let Some(id) = renderer.slot_name()
|
|
91
|
+
{
|
|
92
|
+
let _ = js_sys::Reflect::set(detail, &JsValue::from_str("panel"), &JsValue::from_str(&id));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
44
96
|
fn dispatch_column_settings_open_changed(
|
|
97
|
+
workspace: &Workspace,
|
|
45
98
|
elem: &HtmlElement,
|
|
46
99
|
open: bool,
|
|
47
100
|
column_name: Option<String>,
|
|
@@ -50,28 +103,47 @@ fn dispatch_column_settings_open_changed(
|
|
|
50
103
|
event_init.set_detail(&JsValue::from(
|
|
51
104
|
json!({"open": open, "column_name": column_name}),
|
|
52
105
|
));
|
|
106
|
+
// Bubble so the event still reaches the host (and any public listeners) even
|
|
107
|
+
// though it's dispatched on a panel's plugin below it.
|
|
108
|
+
event_init.set_bubbles(true);
|
|
53
109
|
let event = web_sys::CustomEvent::new_with_event_init_dict(
|
|
54
110
|
"perspective-toggle-column-settings",
|
|
55
111
|
&event_init,
|
|
56
|
-
)
|
|
112
|
+
)
|
|
113
|
+
.unwrap();
|
|
57
114
|
|
|
58
|
-
|
|
59
|
-
|
|
115
|
+
// Dispatch on the ACTIVE panel's plugin, not the shared host. The merged
|
|
116
|
+
// viewer hosts every panel's plugin under one element, and each datagrid
|
|
117
|
+
// listens for this event on itself — so dispatching on the host (which the
|
|
118
|
+
// event bubbles to) would highlight EVERY datagrid. The column settings
|
|
119
|
+
// apply to the active panel, so scope the highlight to its plugin; fall back
|
|
120
|
+
// to the host if none is drawn.
|
|
121
|
+
let target: web_sys::EventTarget = workspace
|
|
122
|
+
.active_id()
|
|
123
|
+
.and_then(|id| workspace.panel(&id))
|
|
124
|
+
.and_then(|panel| panel.renderer.active_plugin())
|
|
125
|
+
.map(|plugin| plugin.unchecked_into())
|
|
126
|
+
.unwrap_or_else(|| elem.clone().unchecked_into());
|
|
60
127
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
event_init.set_detail(plugin);
|
|
64
|
-
let event =
|
|
65
|
-
web_sys::CustomEvent::new_with_event_init_dict("perspective-plugin-update", &event_init);
|
|
128
|
+
target.dispatch_event(&event).unwrap();
|
|
129
|
+
}
|
|
66
130
|
|
|
67
|
-
|
|
131
|
+
fn dispatch_plugin_changed(
|
|
132
|
+
elem: &HtmlElement,
|
|
133
|
+
renderer: &Renderer,
|
|
134
|
+
plugin: &JsPerspectiveViewerPlugin,
|
|
135
|
+
) {
|
|
136
|
+
// Detail is the plugin element itself (identity is via `event.target`, the
|
|
137
|
+
// panel's plugin — see `panel_target`).
|
|
138
|
+
let _ = dispatch_panel_event(elem, renderer, "plugin-update", plugin.as_ref());
|
|
68
139
|
}
|
|
69
140
|
|
|
70
|
-
/// Per-
|
|
71
|
-
///
|
|
72
|
-
///
|
|
73
|
-
///
|
|
74
|
-
///
|
|
141
|
+
/// Per-panel memoized config-change dispatcher. The dedup cell now lives on the
|
|
142
|
+
/// `Session` (per panel) rather than the `Presentation` (per element), so N
|
|
143
|
+
/// panels don't cross-suppress each other's `config-update`s. The event is
|
|
144
|
+
/// dispatched on the panel's plugin (bubbling to the host), so `event.target`
|
|
145
|
+
/// identifies the panel; `detail` remains the bare [`ViewerConfig`] — NOT
|
|
146
|
+
/// wrapped — so `viewer.restore(e.detail)` round-trips unchanged.
|
|
75
147
|
fn dispatch_config_update(
|
|
76
148
|
elem: &HtmlElement,
|
|
77
149
|
session: &Session,
|
|
@@ -80,47 +152,77 @@ fn dispatch_config_update(
|
|
|
80
152
|
) {
|
|
81
153
|
clone!(session, renderer, presentation);
|
|
82
154
|
let elem = elem.clone();
|
|
83
|
-
|
|
84
|
-
|
|
155
|
+
let tracker = session.clone();
|
|
156
|
+
tracker.track_dispatch(async move {
|
|
157
|
+
let viewer_config = renderer
|
|
158
|
+
.clone()
|
|
159
|
+
.with_lock(async { get_viewer_config(&session, &renderer, &presentation).await })
|
|
160
|
+
.await?;
|
|
161
|
+
|
|
85
162
|
if viewer_config.view_config != Default::default()
|
|
86
|
-
&& Some(&viewer_config) !=
|
|
163
|
+
&& Some(&viewer_config) != session.last_dispatched_config.borrow().as_deref()
|
|
87
164
|
{
|
|
88
|
-
let
|
|
165
|
+
let viewer_config = std::rc::Rc::new(viewer_config);
|
|
166
|
+
*session.last_dispatched_config.borrow_mut() = Some(viewer_config.clone());
|
|
167
|
+
let memo = std::cell::RefCell::new(None);
|
|
168
|
+
let get_config = Closure::<dyn Fn() -> Result<JsValue, JsValue>>::new(move || {
|
|
169
|
+
let mut memo = memo.borrow_mut();
|
|
170
|
+
if memo.is_none() {
|
|
171
|
+
*memo = Some(JsValue::from_serde_ext(&*viewer_config).map_err(JsValue::from)?);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Ok(memo.as_ref().unwrap().clone())
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
let detail = js_sys::Object::new();
|
|
178
|
+
js_sys::Reflect::set(
|
|
179
|
+
&detail,
|
|
180
|
+
&JsValue::from_str("getConfig"),
|
|
181
|
+
get_config.as_ref(),
|
|
182
|
+
)?;
|
|
89
183
|
let event_init = web_sys::CustomEventInit::new();
|
|
90
|
-
event_init.set_detail(&
|
|
184
|
+
event_init.set_detail(&detail);
|
|
185
|
+
event_init.set_bubbles(true);
|
|
186
|
+
event_init.set_composed(true);
|
|
91
187
|
let event = web_sys::CustomEvent::new_with_event_init_dict(
|
|
92
188
|
"perspective-config-update",
|
|
93
189
|
&event_init,
|
|
94
|
-
)
|
|
190
|
+
)?;
|
|
95
191
|
|
|
96
|
-
|
|
97
|
-
|
|
192
|
+
panel_target(&elem, &renderer).dispatch_event(&event)?;
|
|
193
|
+
drop(get_config);
|
|
98
194
|
}
|
|
99
195
|
|
|
100
196
|
Ok(())
|
|
101
197
|
});
|
|
102
198
|
}
|
|
103
199
|
|
|
104
|
-
/// Wire PubSub channels
|
|
105
|
-
/// `perspective-*` `CustomEvent` set on `elem`.
|
|
106
|
-
///
|
|
107
|
-
///
|
|
108
|
-
|
|
200
|
+
/// Wire the ELEMENT-level PubSub channels (`Presentation`-driven, not tied to
|
|
201
|
+
/// any one panel) to the `perspective-*` `CustomEvent` set on `elem`. Wired
|
|
202
|
+
/// ONCE for the element's lifetime. The config-update-bearing events
|
|
203
|
+
/// (theme/settings) emit for the **active** panel, resolved from `workspace`
|
|
204
|
+
/// at fire time. The returned `Vec<Subscription>` must outlive the element.
|
|
205
|
+
pub fn wire_element_events(
|
|
109
206
|
elem: &HtmlElement,
|
|
110
|
-
session: &Session,
|
|
111
|
-
renderer: &Renderer,
|
|
112
207
|
presentation: &Presentation,
|
|
208
|
+
workspace: &Workspace,
|
|
113
209
|
) -> Vec<Subscription> {
|
|
114
210
|
let theme_sub = presentation.theme_config_updated.add_listener({
|
|
115
|
-
clone!(elem,
|
|
116
|
-
move |_|
|
|
211
|
+
clone!(elem, presentation, workspace);
|
|
212
|
+
move |_| {
|
|
213
|
+
if let Some(panel) = workspace.active_panel() {
|
|
214
|
+
dispatch_config_update(&elem, &panel.session, &panel.renderer, &presentation);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
117
217
|
});
|
|
118
218
|
|
|
119
219
|
let settings_sub = presentation.settings_open_changed.add_listener({
|
|
120
|
-
clone!(elem,
|
|
220
|
+
clone!(elem, presentation, workspace);
|
|
121
221
|
move |open: bool| {
|
|
122
222
|
dispatch_event(&elem, "toggle-settings", open).unwrap();
|
|
123
|
-
|
|
223
|
+
if let Some(panel) = workspace.active_panel() {
|
|
224
|
+
dispatch_config_update(&elem, &panel.session, &panel.renderer, &presentation);
|
|
225
|
+
}
|
|
124
226
|
}
|
|
125
227
|
});
|
|
126
228
|
|
|
@@ -132,22 +234,73 @@ pub fn wire_custom_events(
|
|
|
132
234
|
});
|
|
133
235
|
|
|
134
236
|
let column_settings_sub = presentation.column_settings_open_changed.add_listener({
|
|
135
|
-
clone!(elem);
|
|
237
|
+
clone!(elem, workspace);
|
|
136
238
|
move |(open, column_name)| {
|
|
137
|
-
dispatch_column_settings_open_changed(&elem, open, column_name);
|
|
239
|
+
dispatch_column_settings_open_changed(&workspace, &elem, open, column_name);
|
|
138
240
|
// column_settings is ethereal; do not change the config
|
|
139
241
|
}
|
|
140
242
|
});
|
|
141
243
|
|
|
244
|
+
let statusbar_ptr_sub = presentation.statusbar_pointer_event.add_listener({
|
|
245
|
+
clone!(elem);
|
|
246
|
+
move |event: PointerEvent| {
|
|
247
|
+
dispatch_event(&elem, &format!("statusbar-{}", event.type_()), &event).unwrap();
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// The element-level global (cross-) filter set changed — masters'
|
|
252
|
+
// selections, chip × / "Clear", role toggles, restore. `detail` is the
|
|
253
|
+
// flattened `Vec<Filter>`; deliberately NOT `perspective-config-update`
|
|
254
|
+
// (these filters are invisible to every panel's config by design).
|
|
255
|
+
let global_filters_sub = workspace.filters_changed().add_listener({
|
|
256
|
+
clone!(elem, workspace);
|
|
257
|
+
move |_: ()| {
|
|
258
|
+
let filters =
|
|
259
|
+
JsValue::from_serde_ext(&workspace.global_filters()).expect("serializable filters");
|
|
260
|
+
dispatch_event(&elem, "global-filter-update", filters).unwrap();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
vec![
|
|
265
|
+
theme_sub,
|
|
266
|
+
before_settings_sub,
|
|
267
|
+
settings_sub,
|
|
268
|
+
column_settings_sub,
|
|
269
|
+
statusbar_ptr_sub,
|
|
270
|
+
global_filters_sub,
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/// Wire ONE panel's `session`/`renderer` PubSub channels to the
|
|
275
|
+
/// `perspective-*` `CustomEvent` set, dispatched on that panel's plugin (so
|
|
276
|
+
/// `event.target` identifies the panel — see [`dispatch_panel_event`]). Called
|
|
277
|
+
/// per panel at creation; the returned subscriptions are owned by the `Panel`
|
|
278
|
+
/// and drop when it is removed, so every panel (seed, `addPanel`, restored)
|
|
279
|
+
/// fires its own events and non-active panels are no longer silent.
|
|
280
|
+
///
|
|
281
|
+
/// Needs no `Workspace`: each handler acts on its own `session`/`renderer`, and
|
|
282
|
+
/// the panel id for annotation is read from `renderer.slot_name()` at fire
|
|
283
|
+
/// time.
|
|
284
|
+
pub fn wire_panel_events(
|
|
285
|
+
elem: &HtmlElement,
|
|
286
|
+
session: &Session,
|
|
287
|
+
renderer: &Renderer,
|
|
288
|
+
presentation: &Presentation,
|
|
289
|
+
) -> Vec<Subscription> {
|
|
142
290
|
let plugin_sub = renderer.plugin_changed.add_listener({
|
|
143
291
|
clone!(elem, session, renderer, presentation);
|
|
144
292
|
move |plugin| {
|
|
145
|
-
dispatch_plugin_changed(&elem, &plugin);
|
|
293
|
+
dispatch_plugin_changed(&elem, &renderer, &plugin);
|
|
146
294
|
dispatch_config_update(&elem, &session, &renderer, &presentation);
|
|
147
295
|
}
|
|
148
296
|
});
|
|
149
297
|
|
|
150
|
-
|
|
298
|
+
// `commit_reconciled` (NOT `view_created`): the config-update event must
|
|
299
|
+
// fire for every reconciled commit — including SKIP/REUSE/paused binds
|
|
300
|
+
// that construct no `View` — or `flush()` has nothing to join (the
|
|
301
|
+
// paused-`load()` case). The dispatcher dedups, so REBUILD's pairing
|
|
302
|
+
// with `view_created` can't double-fire it.
|
|
303
|
+
let view_sub = session.commit_reconciled.add_listener({
|
|
151
304
|
clone!(elem, session, renderer, presentation);
|
|
152
305
|
move |_| dispatch_config_update(&elem, &session, &renderer, &presentation)
|
|
153
306
|
});
|
|
@@ -158,13 +311,14 @@ pub fn wire_custom_events(
|
|
|
158
311
|
});
|
|
159
312
|
|
|
160
313
|
let unload_sub = session.table_unloaded.add_listener({
|
|
161
|
-
clone!(elem);
|
|
314
|
+
clone!(elem, renderer);
|
|
162
315
|
move |x: bool| {
|
|
163
|
-
if !x {
|
|
164
|
-
|
|
316
|
+
let name = if !x {
|
|
317
|
+
"table-delete-before"
|
|
165
318
|
} else {
|
|
166
|
-
|
|
167
|
-
}
|
|
319
|
+
"table-delete"
|
|
320
|
+
};
|
|
321
|
+
let _ = dispatch_panel_event(&elem, &renderer, name, &JsValue::UNDEFINED);
|
|
168
322
|
}
|
|
169
323
|
});
|
|
170
324
|
|
|
@@ -172,7 +326,8 @@ pub fn wire_custom_events(
|
|
|
172
326
|
clone!(elem, session, renderer, presentation);
|
|
173
327
|
move |window: Option<ViewWindow>| {
|
|
174
328
|
let detail = JsValue::from_serde_ext(&window).unwrap();
|
|
175
|
-
|
|
329
|
+
annotate_panel(&detail, &renderer);
|
|
330
|
+
let _ = dispatch_panel_event(&elem, &renderer, "select", &detail);
|
|
176
331
|
dispatch_config_update(&elem, &session, &renderer, &presentation);
|
|
177
332
|
}
|
|
178
333
|
});
|
|
@@ -181,28 +336,25 @@ pub fn wire_custom_events(
|
|
|
181
336
|
clone!(elem, session, renderer, presentation);
|
|
182
337
|
move |cfg: ColumnConfigMap| {
|
|
183
338
|
let detail = JsValue::from_serde_ext(&cfg).unwrap();
|
|
184
|
-
|
|
339
|
+
annotate_panel(&detail, &renderer);
|
|
340
|
+
let _ = dispatch_panel_event(&elem, &renderer, "column-style-change", &detail);
|
|
185
341
|
dispatch_config_update(&elem, &session, &renderer, &presentation);
|
|
186
342
|
}
|
|
187
343
|
});
|
|
188
344
|
|
|
189
345
|
let status_click_sub = session.status_indicator_clicked.add_listener({
|
|
190
|
-
clone!(elem);
|
|
191
|
-
move |_|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
346
|
+
clone!(elem, renderer);
|
|
347
|
+
move |_| {
|
|
348
|
+
let _ = dispatch_panel_event(
|
|
349
|
+
&elem,
|
|
350
|
+
&renderer,
|
|
351
|
+
"status-indicator-click",
|
|
352
|
+
&JsValue::UNDEFINED,
|
|
353
|
+
);
|
|
198
354
|
}
|
|
199
355
|
});
|
|
200
356
|
|
|
201
357
|
vec![
|
|
202
|
-
theme_sub,
|
|
203
|
-
before_settings_sub,
|
|
204
|
-
settings_sub,
|
|
205
|
-
column_settings_sub,
|
|
206
358
|
plugin_sub,
|
|
207
359
|
view_sub,
|
|
208
360
|
title_sub,
|
|
@@ -210,6 +362,5 @@ pub fn wire_custom_events(
|
|
|
210
362
|
select_sub,
|
|
211
363
|
column_style_sub,
|
|
212
364
|
status_click_sub,
|
|
213
|
-
statusbar_ptr_sub,
|
|
214
365
|
]
|
|
215
366
|
}
|
package/src/rust/js/mod.rs
CHANGED
|
@@ -19,10 +19,12 @@ pub mod clipboard_item;
|
|
|
19
19
|
mod intersection_observer;
|
|
20
20
|
mod mimetype;
|
|
21
21
|
pub mod plugin;
|
|
22
|
+
pub mod regular_layout;
|
|
22
23
|
pub mod resize_observer;
|
|
23
24
|
|
|
24
25
|
pub use self::clipboard::*;
|
|
25
26
|
pub use self::intersection_observer::*;
|
|
26
27
|
pub use self::mimetype::*;
|
|
27
28
|
pub use self::plugin::*;
|
|
29
|
+
pub use self::regular_layout::*;
|
|
28
30
|
pub use self::resize_observer::*;
|