@perspective-dev/viewer 4.0.1 → 4.1.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 +2 -2
- package/dist/cdn/perspective-viewer.js.map +4 -4
- 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/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 +23 -2
- package/dist/esm/perspective-viewer.d.ts +2 -7
- package/dist/esm/perspective-viewer.inline.js +2 -2
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +2 -2
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/plugin.d.ts +1 -1
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +1 -0
- package/dist/wasm/perspective-viewer.d.ts +218 -46
- package/dist/wasm/perspective-viewer.js +1250 -761
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +38 -19
- package/package.json +1 -1
- package/src/less/containers/scroll-panel.less +0 -1
- package/src/less/plugin-selector.less +15 -5
- package/src/less/status-bar.less +75 -27
- package/src/less/viewer.less +140 -58
- package/src/rust/components/column_dropdown.rs +21 -21
- package/src/rust/components/column_selector/active_column.rs +131 -120
- package/src/rust/components/column_selector/add_expression_button.rs +5 -0
- package/src/rust/components/column_selector/aggregate_selector.rs +8 -4
- package/src/rust/components/column_selector/config_selector.rs +170 -161
- package/src/rust/components/column_selector/empty_column.rs +16 -11
- package/src/rust/components/column_selector/{expression_toolbar.rs → expr_edit_button.rs} +7 -0
- package/src/rust/components/column_selector/filter_column.rs +195 -194
- package/src/rust/components/column_selector/inactive_column.rs +82 -67
- package/src/rust/components/column_selector/pivot_column.rs +16 -11
- package/src/rust/components/column_selector/sort_column.rs +9 -7
- package/src/rust/components/column_selector.rs +42 -37
- package/src/rust/components/column_settings_sidebar/save_settings.rs +3 -1
- package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +58 -0
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +6 -6
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +2 -94
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +111 -0
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +3 -3
- package/src/rust/components/column_settings_sidebar/style_tab.rs +23 -83
- package/src/rust/components/{column_settings_sidebar/sidebar.rs → column_settings_sidebar.rs} +198 -171
- package/src/rust/components/containers/dragdrop_list.rs +20 -20
- package/src/rust/components/containers/dropdown_menu.rs +4 -6
- package/src/rust/components/containers/mod.rs +1 -4
- package/src/rust/components/containers/scroll_panel.rs +80 -80
- package/src/rust/components/containers/scroll_panel_item.rs +36 -36
- package/src/rust/components/containers/select.rs +46 -44
- package/src/rust/components/containers/sidebar.rs +3 -19
- package/src/rust/components/{column_settings_sidebar/style_tab/symbol/symbol_config.rs → containers/sidebar_close_button.rs} +15 -9
- package/src/rust/components/containers/split_panel.rs +212 -200
- package/src/rust/components/containers/tab_list.rs +11 -11
- package/src/rust/components/copy_dropdown.rs +22 -25
- package/src/rust/components/datetime_column_style/custom.rs +19 -19
- package/src/rust/components/datetime_column_style/simple.rs +13 -14
- package/src/rust/components/datetime_column_style.rs +75 -76
- package/src/rust/components/editable_header.rs +18 -14
- package/src/rust/components/empty_row.rs +5 -5
- package/src/rust/components/export_dropdown.rs +42 -42
- package/src/rust/components/expression_editor.rs +25 -19
- package/src/rust/components/filter_dropdown.rs +22 -22
- package/src/rust/components/font_loader.rs +11 -9
- package/src/rust/components/form/code_editor.rs +106 -105
- package/src/rust/components/form/color_range_selector.rs +14 -12
- package/src/rust/components/form/color_selector.rs +3 -1
- package/src/rust/components/form/debug.rs +95 -94
- package/src/rust/components/form/highlight.rs +5 -3
- package/src/rust/components/form/mod.rs +3 -2
- package/src/rust/components/form/optional_field.rs +2 -2
- package/src/rust/components/form/{select_field.rs → select_enum_field.rs} +1 -46
- package/src/rust/components/form/select_value_field.rs +64 -0
- package/src/rust/components/function_dropdown.rs +21 -21
- package/src/rust/components/main_panel.rs +219 -0
- package/src/rust/components/mod.rs +6 -6
- package/src/rust/components/modal.rs +42 -42
- package/src/rust/components/number_column_style.rs +34 -88
- package/src/rust/components/plugin_selector.rs +22 -25
- package/src/rust/components/render_warning.rs +9 -6
- package/src/rust/components/settings_panel.rs +82 -0
- package/src/rust/components/status_bar.rs +250 -146
- package/src/rust/components/status_bar_counter.rs +26 -119
- package/src/rust/components/status_indicator.rs +95 -79
- package/src/rust/components/string_column_style.rs +45 -45
- package/src/rust/components/style/style_provider.rs +1 -15
- package/src/rust/components/style_controls/number_string_format/digits_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format/misc_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format.rs +45 -46
- package/src/rust/components/type_icon.rs +14 -11
- package/src/rust/components/viewer.rs +241 -384
- package/src/rust/config/columns_config.rs +2 -2
- package/src/rust/config/datetime_column_style.rs +1 -6
- package/src/rust/config/mod.rs +1 -0
- package/src/rust/config/number_column_style.rs +0 -6
- package/src/rust/config/number_string_format.rs +27 -4
- package/src/rust/config/viewer_config.rs +27 -167
- package/src/rust/custom_elements/copy_dropdown.rs +14 -6
- package/src/rust/custom_elements/export_dropdown.rs +15 -7
- package/src/rust/custom_elements/filter_dropdown.rs +4 -4
- package/src/rust/custom_elements/mod.rs +3 -0
- package/src/rust/custom_elements/viewer.rs +353 -161
- package/src/rust/custom_events.rs +55 -32
- package/src/rust/dragdrop.rs +4 -24
- package/src/rust/exprtk/cursor.rs +10 -1
- package/src/rust/exprtk/mod.rs +2 -0
- package/src/rust/exprtk/tokenize.rs +20 -3
- package/src/rust/js/clipboard.rs +2 -2
- package/src/rust/js/mimetype.rs +2 -7
- package/src/rust/js/mod.rs +0 -1
- package/src/rust/js/plugin.rs +7 -0
- package/src/rust/lib.rs +18 -5
- package/src/rust/model/column_locator.rs +82 -0
- package/src/rust/model/columns_iter_set.rs +1 -0
- package/src/rust/model/copy_export.rs +50 -14
- package/src/rust/model/edit_expression.rs +2 -5
- package/src/rust/model/eject.rs +41 -0
- package/src/rust/model/get_viewer_config.rs +4 -28
- package/src/rust/model/intersection_observer.rs +20 -8
- package/src/rust/model/mod.rs +11 -4
- package/src/rust/model/plugin_column_styles.rs +0 -31
- package/src/rust/model/reset_all.rs +38 -0
- package/src/rust/model/resize_observer.rs +34 -7
- package/src/rust/model/restore_and_render.rs +12 -7
- package/src/rust/{utils/scope.rs → model/send_plugin_config.rs} +32 -35
- package/src/rust/model/structural.rs +194 -23
- package/src/rust/model/update_and_render.rs +14 -4
- package/src/rust/{model/create_col.rs → presentation/column_locator.rs} +73 -42
- package/src/rust/{utils/wasm_abi.rs → presentation/sheets.rs} +54 -40
- package/src/rust/presentation.rs +60 -119
- package/src/rust/renderer/activate.rs +20 -5
- package/src/rust/renderer/limits.rs +0 -149
- package/src/rust/renderer/render_timer.rs +1 -1
- package/src/rust/renderer.rs +34 -18
- package/src/rust/root.rs +50 -0
- package/src/rust/session/column_defaults_update.rs +4 -4
- package/src/rust/session/drag_drop_update.rs +1 -1
- package/src/rust/session/metadata.rs +3 -17
- package/src/rust/session/replace_expression_update.rs +1 -2
- package/src/rust/session.rs +162 -82
- package/src/rust/utils/browser/blob.rs +16 -2
- package/src/rust/utils/browser/download.rs +1 -0
- package/src/rust/{components/column_settings_sidebar/mod.rs → utils/browser/dragdrop.rs} +14 -5
- package/src/rust/utils/browser/mod.rs +8 -4
- package/src/rust/utils/browser/selection.rs +5 -0
- package/src/rust/utils/custom_element.rs +28 -13
- package/src/rust/utils/datetime.rs +5 -0
- package/src/rust/utils/debounce.rs +7 -1
- package/src/rust/utils/hooks/use_async_callback.rs +7 -17
- package/src/rust/utils/mod.rs +28 -40
- package/src/rust/utils/number_format.rs +6 -5
- package/src/rust/utils/pubsub.rs +15 -10
- package/src/rust/utils/weak_scope.rs +11 -1
- package/src/svg/bookmark-icon.svg +4 -0
- package/src/svg/drag-handle copy.svg +10 -0
- package/src/svg/drawer-tab-hover.svg +5 -7
- package/src/svg/drawer-tab-invert-hover.svg +4 -8
- package/src/svg/drawer-tab-invert.svg +4 -7
- package/src/svg/drawer-tab.svg +4 -6
- package/src/svg/status_ok.svg +24 -24
- package/src/ts/extensions.ts +51 -3
- package/src/ts/perspective-viewer.ts +2 -14
- package/src/ts/plugin.ts +1 -1
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +0 -177
- package/src/rust/components/containers/tests/mod.rs +0 -11
- package/src/rust/components/containers/tests/split_panel.rs +0 -91
- package/src/rust/js/testing.rs +0 -149
- package/src/rust/utils/tee.rs +0 -88
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-9a89352df1552d2b → perspective-viewer-0d326a25c1022412}/inline4.js +0 -0
- /package/src/rust/components/{style_controls.rs → style_controls/mod.rs} +0 -0
- /package/src/rust/{components/containers → config}/kvpair.rs +0 -0
package/src/rust/presentation.rs
CHANGED
|
@@ -10,26 +10,54 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
mod column_locator;
|
|
14
|
+
mod sheets;
|
|
15
|
+
|
|
13
16
|
use std::cell::RefCell;
|
|
14
17
|
use std::collections::{HashMap, HashSet};
|
|
15
18
|
use std::ops::Deref;
|
|
16
19
|
use std::rc::Rc;
|
|
17
20
|
|
|
18
21
|
use async_lock::Mutex;
|
|
19
|
-
use perspective_js::utils::{ApiFuture, ApiResult
|
|
22
|
+
use perspective_js::utils::{ApiFuture, ApiResult};
|
|
20
23
|
use wasm_bindgen::prelude::*;
|
|
21
24
|
use web_sys::*;
|
|
22
25
|
use yew::html::ImplicitClone;
|
|
23
26
|
|
|
24
|
-
use
|
|
25
|
-
use crate::components::viewer::ColumnLocator;
|
|
27
|
+
pub use self::column_locator::{ColumnLocator, ColumnSettingsTab, ColumnTab, OpenColumnSettings};
|
|
26
28
|
use crate::config::{ColumnConfigUpdate, ColumnConfigValueUpdate, ColumnConfigValues};
|
|
27
29
|
use crate::utils::*;
|
|
28
30
|
|
|
31
|
+
pub type ColumnConfigMap = HashMap<String, ColumnConfigValues>;
|
|
32
|
+
|
|
29
33
|
/// The available themes as detected in the browser environment or set
|
|
30
34
|
/// explicitly when CORS prevents detection. Detection is expensive and
|
|
31
35
|
/// typically must be performed only once, when `document.styleSheets` is
|
|
32
36
|
/// up-to-date.
|
|
37
|
+
#[derive(Default)]
|
|
38
|
+
struct ThemeData {
|
|
39
|
+
themes: Option<Vec<String>>,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Actual presentations tate struct with some fields hidden.
|
|
43
|
+
pub struct PresentationHandle {
|
|
44
|
+
viewer_elem: HtmlElement,
|
|
45
|
+
theme_data: Mutex<ThemeData>,
|
|
46
|
+
is_settings_open: RefCell<bool>,
|
|
47
|
+
open_column_settings: RefCell<OpenColumnSettings>,
|
|
48
|
+
columns_config: RefCell<ColumnConfigMap>,
|
|
49
|
+
is_workspace: RefCell<Option<bool>>,
|
|
50
|
+
pub settings_open_changed: PubSub<bool>,
|
|
51
|
+
pub settings_before_open_changed: PubSub<bool>,
|
|
52
|
+
pub column_settings_open_changed: PubSub<(bool, Option<String>)>,
|
|
53
|
+
pub column_settings_updated: PubSub<JsValue>,
|
|
54
|
+
pub theme_config_updated: PubSub<(Rc<Vec<String>>, Option<usize>)>,
|
|
55
|
+
pub visibility_changed: PubSub<bool>,
|
|
56
|
+
pub on_eject: PubSub<()>,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// State object responsible for the non-persistable/gui element state,
|
|
60
|
+
/// including Themes, panel open state and realtive size, title, etc.
|
|
33
61
|
#[derive(Clone)]
|
|
34
62
|
pub struct Presentation(Rc<PresentationHandle>);
|
|
35
63
|
|
|
@@ -49,74 +77,45 @@ impl Deref for Presentation {
|
|
|
49
77
|
|
|
50
78
|
impl ImplicitClone for Presentation {}
|
|
51
79
|
|
|
52
|
-
#[derive(Clone, Default, Debug, PartialEq)]
|
|
53
|
-
pub struct OpenColumnSettings {
|
|
54
|
-
pub locator: Option<ColumnLocator>,
|
|
55
|
-
pub tab: Option<ColumnSettingsTab>,
|
|
56
|
-
}
|
|
57
|
-
impl OpenColumnSettings {
|
|
58
|
-
pub fn name(&self) -> Option<String> {
|
|
59
|
-
self.locator
|
|
60
|
-
.as_ref()
|
|
61
|
-
.and_then(|l| l.name())
|
|
62
|
-
.map(|s| s.to_owned())
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
pub type ColumnConfigMap = HashMap<String, ColumnConfigValues>;
|
|
67
|
-
|
|
68
|
-
pub struct PresentationHandle {
|
|
69
|
-
viewer_elem: HtmlElement,
|
|
70
|
-
theme_data: Mutex<ThemeData>,
|
|
71
|
-
name: RefCell<Option<String>>,
|
|
72
|
-
is_settings_open: RefCell<bool>,
|
|
73
|
-
open_column_settings: RefCell<OpenColumnSettings>,
|
|
74
|
-
is_workspace: RefCell<Option<bool>>,
|
|
75
|
-
columns_config: RefCell<ColumnConfigMap>,
|
|
76
|
-
pub settings_open_changed: PubSub<bool>,
|
|
77
|
-
pub column_settings_open_changed: PubSub<(bool, Option<String>)>,
|
|
78
|
-
pub column_settings_updated: PubSub<JsValue>,
|
|
79
|
-
pub theme_config_updated: PubSub<(Rc<Vec<String>>, Option<usize>)>,
|
|
80
|
-
pub title_changed: PubSub<Option<String>>,
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
#[derive(Default)]
|
|
84
|
-
pub struct ThemeData {
|
|
85
|
-
themes: Option<Vec<String>>,
|
|
86
|
-
}
|
|
87
|
-
|
|
88
80
|
impl Presentation {
|
|
89
81
|
pub fn new(elem: &HtmlElement) -> Self {
|
|
90
82
|
let theme = Self(Rc::new(PresentationHandle {
|
|
91
83
|
viewer_elem: elem.clone(),
|
|
92
|
-
name: Default::default(),
|
|
93
84
|
theme_data: Default::default(),
|
|
85
|
+
is_workspace: Default::default(),
|
|
94
86
|
settings_open_changed: Default::default(),
|
|
87
|
+
settings_before_open_changed: Default::default(),
|
|
95
88
|
column_settings_open_changed: Default::default(),
|
|
96
89
|
column_settings_updated: Default::default(),
|
|
97
90
|
columns_config: Default::default(),
|
|
98
91
|
is_settings_open: Default::default(),
|
|
99
|
-
is_workspace: Default::default(),
|
|
100
92
|
open_column_settings: Default::default(),
|
|
101
93
|
theme_config_updated: PubSub::default(),
|
|
102
|
-
|
|
94
|
+
on_eject: PubSub::default(),
|
|
95
|
+
visibility_changed: PubSub::default(),
|
|
103
96
|
}));
|
|
104
97
|
|
|
105
98
|
ApiFuture::spawn(theme.clone().init());
|
|
106
99
|
theme
|
|
107
100
|
}
|
|
108
101
|
|
|
109
|
-
pub fn
|
|
110
|
-
self.
|
|
102
|
+
pub fn is_visible(&self) -> bool {
|
|
103
|
+
self.viewer_elem
|
|
104
|
+
.offset_parent()
|
|
105
|
+
.map(|x| !x.is_null())
|
|
106
|
+
.unwrap_or(false)
|
|
111
107
|
}
|
|
112
108
|
|
|
113
|
-
pub fn
|
|
114
|
-
self.
|
|
115
|
-
self.title_changed.emit(title);
|
|
109
|
+
pub fn is_active(&self, elem: &Option<Element>) -> bool {
|
|
110
|
+
elem.is_some() && &self.viewer_elem.shadow_root().unwrap().active_element() == elem
|
|
116
111
|
}
|
|
117
112
|
|
|
118
113
|
pub fn get_is_workspace(&self) -> bool {
|
|
119
114
|
if self.is_workspace.borrow().is_none() {
|
|
115
|
+
if !self.viewer_elem.is_connected() {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
120
119
|
let is_workspace = self
|
|
121
120
|
.viewer_elem
|
|
122
121
|
.parent_element()
|
|
@@ -139,15 +138,16 @@ impl Presentation {
|
|
|
139
138
|
*self.is_settings_open.borrow()
|
|
140
139
|
}
|
|
141
140
|
|
|
142
|
-
pub fn
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
self.
|
|
147
|
-
self.settings_open_changed.emit(open_state);
|
|
141
|
+
pub fn set_settings_before_open(&self, open: bool) {
|
|
142
|
+
if *self.is_settings_open.borrow() != open {
|
|
143
|
+
*self.is_settings_open.borrow_mut() = open;
|
|
144
|
+
self.set_settings_attribute(open);
|
|
145
|
+
self.settings_before_open_changed.emit(open);
|
|
148
146
|
}
|
|
147
|
+
}
|
|
149
148
|
|
|
150
|
-
|
|
149
|
+
pub fn set_settings_open(&self, open: bool) {
|
|
150
|
+
self.settings_open_changed.emit(open);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/// Sets the currently opened column settings. Emits an internal event on
|
|
@@ -178,7 +178,7 @@ impl Presentation {
|
|
|
178
178
|
let mut data = self.0.theme_data.lock().await;
|
|
179
179
|
if data.themes.is_none() {
|
|
180
180
|
await_dom_loaded().await?;
|
|
181
|
-
let themes = get_theme_names(&self.0.viewer_elem)?;
|
|
181
|
+
let themes = sheets::get_theme_names(&self.0.viewer_elem)?;
|
|
182
182
|
data.themes = Some(themes);
|
|
183
183
|
}
|
|
184
184
|
|
|
@@ -230,6 +230,7 @@ impl Presentation {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
pub async fn reset_theme(&self) -> ApiResult<()> {
|
|
233
|
+
*self.0.is_workspace.borrow_mut() = None;
|
|
233
234
|
let themes = self.get_available_themes().await?;
|
|
234
235
|
let default_theme = themes.first().map(|x| x.as_str());
|
|
235
236
|
self.set_theme_name(default_theme).await?;
|
|
@@ -242,10 +243,10 @@ impl Presentation {
|
|
|
242
243
|
/// A `bool` indicating whether the internal state changed.
|
|
243
244
|
pub async fn set_theme_name(&self, theme: Option<&str>) -> ApiResult<bool> {
|
|
244
245
|
let (themes, selected) = self.get_selected_theme_config().await?;
|
|
245
|
-
if let Some(x) = selected
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
if let Some(x) = selected {
|
|
247
|
+
if themes.get(x).map(|x| x.as_str()) == theme {
|
|
248
|
+
return Ok(false);
|
|
249
|
+
}
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
let index = if let Some(theme) = theme {
|
|
@@ -308,63 +309,3 @@ impl Presentation {
|
|
|
308
309
|
}
|
|
309
310
|
}
|
|
310
311
|
}
|
|
311
|
-
|
|
312
|
-
macro_rules! iter_index {
|
|
313
|
-
($x:expr) => {
|
|
314
|
-
(0..$x.length()).map(|x| $x.item(x))
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
fn fill_rule_theme_names(
|
|
319
|
-
themes: &mut Vec<String>,
|
|
320
|
-
rule: &Option<CssRule>,
|
|
321
|
-
elem: &HtmlElement,
|
|
322
|
-
) -> ApiResult<()> {
|
|
323
|
-
if let Some(rule) = rule.as_ref().into_apierror()?.dyn_ref::<CssStyleRule>() {
|
|
324
|
-
let txt = rule.selector_text();
|
|
325
|
-
if elem.matches(&txt)? {
|
|
326
|
-
let style = rule.style();
|
|
327
|
-
let x = (0..style.length()).map(|x| style.item(x));
|
|
328
|
-
for property in x {
|
|
329
|
-
if property == "--theme-name" {
|
|
330
|
-
let name = style.get_property_value("--theme-name")?;
|
|
331
|
-
let trimmed = name.trim();
|
|
332
|
-
themes.push(trimmed[1..trimmed.len() - 1].to_owned());
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
Ok(())
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
fn fill_sheet_theme_names(
|
|
342
|
-
themes: &mut Vec<String>,
|
|
343
|
-
sheet: &Option<StyleSheet>,
|
|
344
|
-
elem: &HtmlElement,
|
|
345
|
-
) -> ApiResult<()> {
|
|
346
|
-
let sheet = sheet
|
|
347
|
-
.as_ref()
|
|
348
|
-
.into_apierror()?
|
|
349
|
-
.unchecked_ref::<CssStyleSheet>();
|
|
350
|
-
|
|
351
|
-
if let Ok(rules) = sheet.css_rules() {
|
|
352
|
-
for rule in iter_index!(&rules) {
|
|
353
|
-
fill_rule_theme_names(themes, &rule, elem).unwrap_or_default();
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
Ok(())
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/// Search the document's `styleSheets` for rules which apply to `elem` and
|
|
361
|
-
/// provide the `--theme-name` CSS custom property.
|
|
362
|
-
fn get_theme_names(elem: &HtmlElement) -> Result<Vec<String>, JsValue> {
|
|
363
|
-
let sheets = global::document().style_sheets();
|
|
364
|
-
let mut themes: Vec<String> = vec![];
|
|
365
|
-
for sheet in iter_index!(sheets) {
|
|
366
|
-
fill_sheet_theme_names(&mut themes, &sheet, elem)?;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
Ok(themes)
|
|
370
|
-
}
|
|
@@ -39,11 +39,26 @@ pub async fn activate_plugin<T>(
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
let result = task.await;
|
|
42
|
-
let first_child = viewer.children().item(0).unwrap();
|
|
43
|
-
if first_child != *plugin.unchecked_ref::<Element>() {
|
|
44
|
-
viewer.remove_child(&first_child)?;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
42
|
html_plugin.style().set_property("opacity", "1")?;
|
|
48
43
|
result
|
|
49
44
|
}
|
|
45
|
+
|
|
46
|
+
pub fn remove_inactive_plugin(
|
|
47
|
+
viewer: &HtmlElement,
|
|
48
|
+
plugin: &JsPerspectiveViewerPlugin,
|
|
49
|
+
plugins: &[JsPerspectiveViewerPlugin],
|
|
50
|
+
) -> ApiResult<()> {
|
|
51
|
+
for idx in 0..viewer.children().length() {
|
|
52
|
+
let elem = viewer.children().item(idx).unwrap();
|
|
53
|
+
if &elem != plugin.unchecked_ref::<Element>()
|
|
54
|
+
&& plugins
|
|
55
|
+
.iter()
|
|
56
|
+
.any(|x| *x.unchecked_ref::<Element>() == elem)
|
|
57
|
+
{
|
|
58
|
+
viewer.remove_child(&elem)?;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Ok(())
|
|
64
|
+
}
|
|
@@ -49,152 +49,3 @@ pub async fn get_row_and_col_limits(
|
|
|
49
49
|
},
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
// #[cfg(test)]
|
|
54
|
-
// mod tests {
|
|
55
|
-
// use super::*;
|
|
56
|
-
|
|
57
|
-
// fn closure_helper<T>(x: T) -> Closure<dyn Fn(JsValue) -> js_sys::Promise>
|
|
58
|
-
// where
|
|
59
|
-
// T: Into<JsValue>,
|
|
60
|
-
// {
|
|
61
|
-
// let val = x.into();
|
|
62
|
-
// Closure::new(move |_: JsValue| {
|
|
63
|
-
// clone!(val);
|
|
64
|
-
// future_to_promise(async move { Ok(val.clone()) })
|
|
65
|
-
// })
|
|
66
|
-
// }
|
|
67
|
-
|
|
68
|
-
// #[wasm_bindgen_test]
|
|
69
|
-
// pub async fn test_emtpy_schema_no_columns() {
|
|
70
|
-
// let closure = closure_helper(0);
|
|
71
|
-
// let closure2 = closure_helper(json!({}));
|
|
72
|
-
// let view = json!({
|
|
73
|
-
// "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
74
|
-
// "num_rows": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
75
|
-
// "schema": closure2.as_ref().unchecked_ref::<JsValue>()
|
|
76
|
-
// })
|
|
77
|
-
// .unchecked_into::<JsPerspectiveView>();
|
|
78
|
-
|
|
79
|
-
// let reqs = ViewConfigRequirements {
|
|
80
|
-
// render_warning: true,
|
|
81
|
-
// ..ViewConfigRequirements::default()
|
|
82
|
-
// };
|
|
83
|
-
// let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
|
|
84
|
-
// &reqs).await.unwrap(); assert_eq!(max_cols, None);
|
|
85
|
-
// assert_eq!(max_rows, None);
|
|
86
|
-
// }
|
|
87
|
-
|
|
88
|
-
// #[wasm_bindgen_test]
|
|
89
|
-
// pub async fn test_columns_do_not_exceed_max_columns() {
|
|
90
|
-
// let closure = closure_helper(1);
|
|
91
|
-
// let closure2 = closure_helper(0);
|
|
92
|
-
// let closure3 = closure_helper(json!({}));
|
|
93
|
-
// let view = json!({
|
|
94
|
-
// "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
95
|
-
// "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
|
|
96
|
-
// "schema": closure3.as_ref().unchecked_ref::<JsValue>()
|
|
97
|
-
// })
|
|
98
|
-
// .unchecked_into::<JsPerspectiveView>();
|
|
99
|
-
|
|
100
|
-
// let reqs = ViewConfigRequirements {
|
|
101
|
-
// max_columns: Some(2),
|
|
102
|
-
// render_warning: true,
|
|
103
|
-
// ..ViewConfigRequirements::default()
|
|
104
|
-
// };
|
|
105
|
-
|
|
106
|
-
// let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
|
|
107
|
-
// &reqs).await.unwrap(); assert_eq!(max_cols, None);
|
|
108
|
-
// assert_eq!(max_rows, None);
|
|
109
|
-
// }
|
|
110
|
-
|
|
111
|
-
// #[wasm_bindgen_test]
|
|
112
|
-
// pub async fn test_columns_exceed_max_columns() {
|
|
113
|
-
// let closure = closure_helper(2);
|
|
114
|
-
// let closure2 = closure_helper(0);
|
|
115
|
-
// let closure3 = closure_helper(json!({}));
|
|
116
|
-
// let view = json!({
|
|
117
|
-
// "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
118
|
-
// "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
|
|
119
|
-
// "schema": closure3.as_ref().unchecked_ref::<JsValue>()
|
|
120
|
-
// })
|
|
121
|
-
// .unchecked_into::<JsPerspectiveView>();
|
|
122
|
-
|
|
123
|
-
// let reqs = ViewConfigRequirements {
|
|
124
|
-
// max_columns: Some(1),
|
|
125
|
-
// render_warning: true,
|
|
126
|
-
// ..ViewConfigRequirements::default()
|
|
127
|
-
// };
|
|
128
|
-
// let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
|
|
129
|
-
// &reqs).await.unwrap(); assert_eq!(max_cols, Some(1));
|
|
130
|
-
// assert_eq!(max_rows, None);
|
|
131
|
-
// }
|
|
132
|
-
|
|
133
|
-
// #[wasm_bindgen_test]
|
|
134
|
-
// pub async fn test_when_schema_columns_are_present() {
|
|
135
|
-
// let closure = closure_helper(100);
|
|
136
|
-
// let closure2 = closure_helper(0);
|
|
137
|
-
// let closure3 = closure_helper(json!({"x": "string", "y": "string"}));
|
|
138
|
-
// let view = json!({
|
|
139
|
-
// "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
140
|
-
// "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
|
|
141
|
-
// "schema": closure3.as_ref().unchecked_ref::<JsValue>()
|
|
142
|
-
// })
|
|
143
|
-
// .unchecked_into::<JsPerspectiveView>();
|
|
144
|
-
|
|
145
|
-
// let reqs = ViewConfigRequirements {
|
|
146
|
-
// max_columns: Some(3),
|
|
147
|
-
// render_warning: true,
|
|
148
|
-
// ..ViewConfigRequirements::default()
|
|
149
|
-
// };
|
|
150
|
-
// let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
|
|
151
|
-
// &reqs).await.unwrap(); assert_eq!(max_cols, Some(4));
|
|
152
|
-
// assert_eq!(max_rows, None);
|
|
153
|
-
// }
|
|
154
|
-
|
|
155
|
-
// #[wasm_bindgen_test]
|
|
156
|
-
// pub async fn test_when_max_cells_exits() {
|
|
157
|
-
// let closure = closure_helper(1);
|
|
158
|
-
// let closure2 = closure_helper(0);
|
|
159
|
-
// let closure3 = closure_helper(json!({}));
|
|
160
|
-
// let view = json!({
|
|
161
|
-
// "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
162
|
-
// "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
|
|
163
|
-
// "schema": closure3.as_ref().unchecked_ref::<JsValue>()
|
|
164
|
-
// })
|
|
165
|
-
// .unchecked_into::<JsPerspectiveView>();
|
|
166
|
-
|
|
167
|
-
// let reqs = ViewConfigRequirements {
|
|
168
|
-
// max_cells: Some(2),
|
|
169
|
-
// render_warning: true,
|
|
170
|
-
// ..ViewConfigRequirements::default()
|
|
171
|
-
// };
|
|
172
|
-
// let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
|
|
173
|
-
// &reqs).await.unwrap(); assert_eq!(max_cols, None);
|
|
174
|
-
// assert_eq!(max_rows, Some(2));
|
|
175
|
-
// }
|
|
176
|
-
|
|
177
|
-
// #[wasm_bindgen_test]
|
|
178
|
-
// pub async fn test_when_columns_exceed_max_columns_and_max_cells_exists()
|
|
179
|
-
// { let closure = closure_helper(4);
|
|
180
|
-
// let closure2 = closure_helper(0);
|
|
181
|
-
// let closure3 = closure_helper(json!({}));
|
|
182
|
-
// let view = json!({
|
|
183
|
-
// "num_columns": closure.as_ref().unchecked_ref::<JsValue>(),
|
|
184
|
-
// "num_rows": closure2.as_ref().unchecked_ref::<JsValue>(),
|
|
185
|
-
// "schema": closure3.as_ref().unchecked_ref::<JsValue>()
|
|
186
|
-
// })
|
|
187
|
-
// .unchecked_into::<JsPerspectiveView>();
|
|
188
|
-
|
|
189
|
-
// let reqs = ViewConfigRequirements {
|
|
190
|
-
// max_columns: Some(2),
|
|
191
|
-
// max_cells: Some(10),
|
|
192
|
-
// render_warning: true,
|
|
193
|
-
// ..ViewConfigRequirements::default()
|
|
194
|
-
// };
|
|
195
|
-
|
|
196
|
-
// let (_, _, max_cols, max_rows) = get_row_and_col_limits(&view,
|
|
197
|
-
// &reqs).await.unwrap(); assert_eq!(max_cols, Some(2));
|
|
198
|
-
// assert_eq!(max_rows, Some(5));
|
|
199
|
-
// }
|
|
200
|
-
// }
|
|
@@ -171,7 +171,7 @@ impl Default for RenderTimerState {
|
|
|
171
171
|
|
|
172
172
|
impl From<&RenderTimerState> for RenderTimerStats {
|
|
173
173
|
fn from(value: &RenderTimerState) -> Self {
|
|
174
|
-
let perf = global::
|
|
174
|
+
let perf = global::performance();
|
|
175
175
|
let now = perf.now();
|
|
176
176
|
let total_time = now - value.start_time;
|
|
177
177
|
RenderTimerStats {
|
package/src/rust/renderer.rs
CHANGED
|
@@ -31,7 +31,8 @@ use std::pin::Pin;
|
|
|
31
31
|
use std::rc::Rc;
|
|
32
32
|
|
|
33
33
|
use futures::future::{join_all, select_all};
|
|
34
|
-
use perspective_client::
|
|
34
|
+
use perspective_client::utils::*;
|
|
35
|
+
use perspective_client::{View, ViewWindow};
|
|
35
36
|
use perspective_js::json;
|
|
36
37
|
use perspective_js::utils::ApiResult;
|
|
37
38
|
use wasm_bindgen::prelude::*;
|
|
@@ -46,12 +47,8 @@ use self::render_timer::*;
|
|
|
46
47
|
use crate::config::*;
|
|
47
48
|
use crate::js::plugin::*;
|
|
48
49
|
use crate::presentation::ColumnConfigMap;
|
|
49
|
-
use crate::session::*;
|
|
50
50
|
use crate::utils::*;
|
|
51
51
|
|
|
52
|
-
#[derive(Clone)]
|
|
53
|
-
pub struct Renderer(Rc<RendererData>);
|
|
54
|
-
|
|
55
52
|
/// Immutable state
|
|
56
53
|
pub struct RendererData {
|
|
57
54
|
plugin_data: RefCell<RendererMutData>,
|
|
@@ -75,6 +72,10 @@ pub struct RendererMutData {
|
|
|
75
72
|
|
|
76
73
|
type RenderLimits = (usize, usize, Option<usize>, Option<usize>);
|
|
77
74
|
|
|
75
|
+
/// The state object responsible for the active [`JsPerspectiveViewerPlugin`].
|
|
76
|
+
#[derive(Clone)]
|
|
77
|
+
pub struct Renderer(Rc<RendererData>);
|
|
78
|
+
|
|
78
79
|
impl Deref for Renderer {
|
|
79
80
|
type Target = RendererData;
|
|
80
81
|
|
|
@@ -135,10 +136,8 @@ impl Renderer {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
pub fn delete(&self) -> ApiResult<()> {
|
|
138
|
-
|
|
139
|
-
self.
|
|
140
|
-
|
|
141
|
-
// self.plugin_data.borrow_mut().metadata = ViewConfigRequirements::default();
|
|
139
|
+
self.get_active_plugin().map(|x| x.delete()).unwrap_or_log();
|
|
140
|
+
self.plugin_data.borrow().viewer_elem.set_inner_text("");
|
|
142
141
|
let new_state = Self::new(&self.plugin_data.borrow().viewer_elem);
|
|
143
142
|
std::mem::swap(
|
|
144
143
|
&mut *self.plugin_data.borrow_mut(),
|
|
@@ -193,6 +192,13 @@ impl Renderer {
|
|
|
193
192
|
Ok(result.unwrap())
|
|
194
193
|
}
|
|
195
194
|
|
|
195
|
+
pub fn is_plugin_activated(&self) -> ApiResult<bool> {
|
|
196
|
+
Ok(self
|
|
197
|
+
.get_active_plugin()?
|
|
198
|
+
.unchecked_ref::<HtmlElement>()
|
|
199
|
+
.is_connected())
|
|
200
|
+
}
|
|
201
|
+
|
|
196
202
|
pub async fn restyle_all(&self, view: &perspective_client::View) -> ApiResult<JsValue> {
|
|
197
203
|
let plugins = self.get_all_plugins();
|
|
198
204
|
let tasks = plugins
|
|
@@ -235,7 +241,6 @@ impl Renderer {
|
|
|
235
241
|
};
|
|
236
242
|
|
|
237
243
|
let idx = self.find_plugin_idx(name).expect("f");
|
|
238
|
-
|
|
239
244
|
let changed = !matches!(
|
|
240
245
|
self.0.borrow().plugins_idx,
|
|
241
246
|
Some(selected_idx) if selected_idx == idx
|
|
@@ -318,19 +323,23 @@ impl Renderer {
|
|
|
318
323
|
}
|
|
319
324
|
|
|
320
325
|
/// This will take a future which _should_ create a new view and then will
|
|
321
|
-
/// draw it.
|
|
322
|
-
|
|
326
|
+
/// draw it. As the `session` closure is asynchronous, it can be cancelled
|
|
327
|
+
/// by returning `None`.
|
|
328
|
+
pub async fn draw(
|
|
329
|
+
&self,
|
|
330
|
+
session: impl Future<Output = ApiResult<Option<View>>>,
|
|
331
|
+
) -> ApiResult<()> {
|
|
323
332
|
self.draw_plugin(session, false).await
|
|
324
333
|
}
|
|
325
334
|
|
|
326
335
|
/// This will update an already existing view
|
|
327
|
-
pub async fn update(&self, session:
|
|
336
|
+
pub async fn update(&self, session: Option<View>) -> ApiResult<()> {
|
|
328
337
|
self.draw_plugin(async { Ok(session) }, true).await
|
|
329
338
|
}
|
|
330
339
|
|
|
331
340
|
async fn draw_plugin(
|
|
332
341
|
&self,
|
|
333
|
-
session: impl Future<Output = ApiResult
|
|
342
|
+
session: impl Future<Output = ApiResult<Option<View>>>,
|
|
334
343
|
is_update: bool,
|
|
335
344
|
) -> ApiResult<()> {
|
|
336
345
|
let timer = self.render_timer();
|
|
@@ -339,9 +348,10 @@ impl Renderer {
|
|
|
339
348
|
set_timeout(timer.get_throttle()).await?;
|
|
340
349
|
}
|
|
341
350
|
|
|
342
|
-
if let Some(view) = session.await
|
|
351
|
+
if let Some(view) = session.await? {
|
|
343
352
|
timer.capture_time(self.draw_view(&view, is_update)).await
|
|
344
353
|
} else {
|
|
354
|
+
tracing::debug!("Render skipped, no `View` attached");
|
|
345
355
|
Ok(())
|
|
346
356
|
}
|
|
347
357
|
};
|
|
@@ -362,17 +372,23 @@ impl Renderer {
|
|
|
362
372
|
let viewer_elem = &self.0.borrow().viewer_elem.clone();
|
|
363
373
|
if is_update {
|
|
364
374
|
let task = plugin.update(view.clone().into(), limits.2, limits.3, false);
|
|
365
|
-
activate_plugin(viewer_elem, &plugin, task).await
|
|
375
|
+
activate_plugin(viewer_elem, &plugin, task).await?;
|
|
366
376
|
} else {
|
|
367
377
|
let task = plugin.draw(view.clone().into(), limits.2, limits.3, false);
|
|
368
|
-
activate_plugin(viewer_elem, &plugin, task).await
|
|
378
|
+
activate_plugin(viewer_elem, &plugin, task).await?;
|
|
369
379
|
}
|
|
380
|
+
|
|
381
|
+
remove_inactive_plugin(
|
|
382
|
+
viewer_elem,
|
|
383
|
+
&plugin,
|
|
384
|
+
self.plugin_data.borrow_mut().plugin_store.plugins(),
|
|
385
|
+
)
|
|
370
386
|
}
|
|
371
387
|
|
|
372
388
|
/// Decide whether to draw plugin or self first based on whether the panel
|
|
373
389
|
/// is opening or closing, then draw with a timeout. If the timeout
|
|
374
390
|
/// triggers, draw self and resolve `on_toggle` but still await the
|
|
375
|
-
/// completion of the draw task
|
|
391
|
+
/// completion of the draw task.
|
|
376
392
|
pub async fn presize(
|
|
377
393
|
&self,
|
|
378
394
|
open: bool,
|
package/src/rust/root.rs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
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::cell::{Ref, RefCell, RefMut};
|
|
14
|
+
use std::rc::Rc;
|
|
15
|
+
|
|
16
|
+
use derivative::Derivative;
|
|
17
|
+
use yew::{AppHandle, Component};
|
|
18
|
+
|
|
19
|
+
#[derive(Default, Derivative)]
|
|
20
|
+
#[derivative(Clone(bound = ""))]
|
|
21
|
+
pub struct Root<T: Component>(Rc<RefCell<Option<AppHandle<T>>>>);
|
|
22
|
+
|
|
23
|
+
impl<T: Component> PartialEq for Root<T> {
|
|
24
|
+
fn eq(&self, other: &Self) -> bool {
|
|
25
|
+
Rc::ptr_eq(&self.0, &other.0)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// We want to use libraries that are designed to require thread-safety, in the
|
|
30
|
+
// JavaScript environment that (currently) does not allow threads. If we were
|
|
31
|
+
// to implement a threaded build, we'd need to replace with true
|
|
32
|
+
// synchronization.
|
|
33
|
+
unsafe impl<T: Component> Send for Root<T> {}
|
|
34
|
+
unsafe impl<T: Component> Sync for Root<T> {}
|
|
35
|
+
|
|
36
|
+
impl<T: Component> Root<T> {
|
|
37
|
+
pub fn new(shadow_root: web_sys::Element, props: T::Properties) -> Self {
|
|
38
|
+
Self(Rc::new(RefCell::new(Some(
|
|
39
|
+
yew::Renderer::with_root_and_props(shadow_root, props).render(),
|
|
40
|
+
))))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
pub fn borrow(&self) -> Ref<'_, Option<AppHandle<T>>> {
|
|
44
|
+
self.0.borrow()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn borrow_mut(&self) -> RefMut<'_, Option<AppHandle<T>>> {
|
|
48
|
+
self.0.borrow_mut()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -111,7 +111,7 @@ pub impl ViewConfigUpdate {
|
|
|
111
111
|
}
|
|
112
112
|
} else if self.columns.is_none() {
|
|
113
113
|
let mut columns = columns.to_vec();
|
|
114
|
-
let initial_len = columns.len();
|
|
114
|
+
let initial_len = self.columns.as_ref().map(|x| x.len()).unwrap_or_default();
|
|
115
115
|
if let Some(last_filled) = columns.iter().rposition(|x| x.is_some()) {
|
|
116
116
|
columns.truncate(last_filled + 1);
|
|
117
117
|
if let ViewConfigRequirements {
|
|
@@ -131,10 +131,10 @@ pub impl ViewConfigUpdate {
|
|
|
131
131
|
.filter(|x| x.is_some())
|
|
132
132
|
.collect::<Vec<_>>();
|
|
133
133
|
}
|
|
134
|
+
}
|
|
134
135
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
136
|
+
if initial_len != columns.len() {
|
|
137
|
+
self.columns = Some(columns);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|