@perspective-dev/viewer 4.3.0 → 4.4.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 (227) hide show
  1. package/dist/cdn/perspective-viewer.js +2 -2
  2. package/dist/cdn/perspective-viewer.js.map +4 -4
  3. package/dist/css/botanical.css +1 -1
  4. package/dist/css/dracula.css +1 -1
  5. package/dist/css/gruvbox-dark.css +1 -1
  6. package/dist/css/gruvbox.css +1 -1
  7. package/dist/css/icons.css +1 -1
  8. package/dist/css/intl/de.css +1 -1
  9. package/dist/css/intl/es.css +1 -1
  10. package/dist/css/intl/fr.css +1 -1
  11. package/dist/css/intl/ja.css +1 -1
  12. package/dist/css/intl/pt.css +1 -1
  13. package/dist/css/intl/zh.css +1 -1
  14. package/dist/css/intl.css +1 -1
  15. package/dist/css/monokai.css +1 -1
  16. package/dist/css/pro-dark.css +1 -1
  17. package/dist/css/pro.css +1 -1
  18. package/dist/css/solarized-dark.css +1 -1
  19. package/dist/css/solarized.css +1 -1
  20. package/dist/css/themes.css +1 -1
  21. package/dist/css/vaporwave.css +1 -1
  22. package/dist/esm/perspective-viewer.inline.js +2 -2
  23. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  24. package/dist/esm/perspective-viewer.js +2 -2
  25. package/dist/esm/perspective-viewer.js.map +4 -4
  26. package/dist/wasm/perspective-viewer.d.ts +57 -53
  27. package/dist/wasm/perspective-viewer.js +190 -165
  28. package/dist/wasm/perspective-viewer.wasm +0 -0
  29. package/dist/wasm/perspective-viewer.wasm.d.ts +17 -18
  30. package/package.json +7 -5
  31. package/src/{less/aggregate-selector.less → css/aggregate-selector.css} +23 -20
  32. package/src/css/column-dropdown.css +109 -0
  33. package/src/{less/column-selector.less → css/column-selector.css} +160 -158
  34. package/src/{less/column-settings-panel.less → css/column-settings-panel.css} +69 -59
  35. package/src/{less/column-style.less → css/column-style.css} +52 -66
  36. package/src/{less/column-symbol-attributes.less → css/column-symbol-attributes.css} +15 -14
  37. package/src/{less/config-selector.less → css/config-selector.css} +151 -135
  38. package/src/{less/containers/dropdown-menu.less → css/containers/dropdown-menu.css} +20 -19
  39. package/src/{less/containers/pairs-list.less → css/containers/pairs-list.css} +13 -12
  40. package/src/{themes/variables.less → css/containers/scroll-panel.css} +25 -22
  41. package/src/{less/containers/split-panel.less → css/containers/split-panel.css} +15 -14
  42. package/src/{less/containers/tabs.less → css/containers/tabs.css} +17 -19
  43. package/src/css/dom/checkbox.css +102 -0
  44. package/src/css/dom/scrollbar.css +35 -0
  45. package/src/{less/dom/select.less → css/dom/select.css} +17 -18
  46. package/src/{less/empty-column.less → css/empty-column.css} +19 -18
  47. package/src/{less/expression-editor.less → css/expression-editor.css} +19 -18
  48. package/src/{less/filter-dropdown.less → css/filter-dropdown.css} +12 -11
  49. package/src/{less/filter-item.less → css/filter-item.css} +16 -15
  50. package/src/{less/form/code-editor.less → css/form/code-editor.css} +26 -30
  51. package/src/{less/form/debug.less → css/form/debug.css} +19 -18
  52. package/src/{less/function-dropdown.less → css/function-dropdown.css} +12 -11
  53. package/src/css/plugin-selector.css +261 -0
  54. package/src/{less/render-warning.less → css/render-warning.css} +18 -17
  55. package/src/{less/status-bar.less → css/status-bar.css} +156 -144
  56. package/src/css/type-icon.css +116 -0
  57. package/src/{less/viewer.less → css/viewer.css} +112 -146
  58. package/src/rust/components/column_dropdown.rs +229 -119
  59. package/src/rust/components/column_selector/active_column.rs +81 -62
  60. package/src/rust/components/column_selector/add_expression_button.rs +1 -0
  61. package/src/rust/components/column_selector/aggregate_selector.rs +25 -15
  62. package/src/rust/components/column_selector/config_selector.rs +315 -199
  63. package/src/rust/components/column_selector/empty_column.rs +2 -2
  64. package/src/rust/components/column_selector/expr_edit_button.rs +8 -2
  65. package/src/rust/components/column_selector/filter_column.rs +37 -26
  66. package/src/rust/components/column_selector/inactive_column.rs +41 -29
  67. package/src/rust/components/column_selector/invalid_column.rs +7 -18
  68. package/src/rust/components/column_selector/pivot_column.rs +11 -5
  69. package/src/rust/components/column_selector/sort_column.rs +23 -13
  70. package/src/rust/components/column_selector.rs +163 -84
  71. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +1 -1
  72. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +3 -2
  73. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +3 -2
  74. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +2 -3
  75. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +7 -1
  76. package/src/rust/components/column_settings_sidebar/style_tab.rs +153 -112
  77. package/src/rust/components/column_settings_sidebar.rs +91 -53
  78. package/src/rust/components/containers/dragdrop_list.rs +2 -1
  79. package/src/rust/components/containers/sidebar_close_button.rs +1 -1
  80. package/src/rust/components/containers/split_panel.rs +1 -0
  81. package/src/rust/components/containers/tab_list.rs +1 -1
  82. package/src/rust/components/copy_dropdown.rs +7 -28
  83. package/src/rust/components/datetime_column_style/custom.rs +2 -2
  84. package/src/rust/components/datetime_column_style/simple.rs +2 -2
  85. package/src/rust/components/datetime_column_style.rs +4 -2
  86. package/src/rust/components/editable_header.rs +7 -4
  87. package/src/rust/components/empty_row.rs +1 -1
  88. package/src/rust/components/export_dropdown.rs +4 -30
  89. package/src/rust/components/expression_editor.rs +19 -10
  90. package/src/rust/components/filter_dropdown.rs +246 -102
  91. package/src/rust/components/font_loader.rs +11 -28
  92. package/src/rust/components/form/code_editor.rs +17 -2
  93. package/src/rust/components/form/color_range_selector.rs +19 -6
  94. package/src/rust/components/form/debug.rs +30 -13
  95. package/src/rust/components/function_dropdown.rs +186 -113
  96. package/src/rust/components/main_panel.rs +71 -89
  97. package/src/rust/components/mod.rs +1 -1
  98. package/src/rust/components/modal.rs +7 -1
  99. package/src/rust/components/number_column_style.rs +22 -7
  100. package/src/rust/components/plugin_selector.rs +34 -102
  101. package/src/rust/components/portal.rs +274 -0
  102. package/src/rust/components/render_warning.rs +72 -123
  103. package/src/rust/components/settings_panel.rs +115 -11
  104. package/src/rust/components/status_bar.rs +222 -98
  105. package/src/rust/components/status_bar_counter.rs +8 -20
  106. package/src/rust/components/status_indicator.rs +64 -114
  107. package/src/rust/components/string_column_style.rs +2 -2
  108. package/src/rust/components/style/style_cache.rs +5 -1
  109. package/src/rust/components/viewer.rs +391 -39
  110. package/src/rust/custom_elements/copy_dropdown.rs +102 -21
  111. package/src/rust/custom_elements/export_dropdown.rs +102 -20
  112. package/src/rust/custom_elements/mod.rs +0 -7
  113. package/src/rust/custom_elements/modal.rs +7 -103
  114. package/src/rust/custom_elements/viewer.rs +99 -35
  115. package/src/rust/custom_events.rs +23 -2
  116. package/src/rust/dragdrop.rs +149 -10
  117. package/src/{less/containers/scroll-panel.less → rust/engines.rs} +15 -13
  118. package/src/rust/js/plugin.rs +1 -1
  119. package/src/rust/lib.rs +5 -4
  120. package/src/rust/presentation/props.rs +39 -0
  121. package/src/rust/presentation/sheets.rs +3 -3
  122. package/src/rust/presentation.rs +44 -8
  123. package/src/rust/renderer/limits.rs +32 -3
  124. package/src/{less/dom/scrollbar.less → rust/renderer/props.rs} +18 -19
  125. package/src/rust/renderer.rs +83 -9
  126. package/src/rust/session/column_defaults_update.rs +1 -1
  127. package/src/rust/session/metadata.rs +23 -2
  128. package/src/rust/session/props.rs +178 -0
  129. package/src/rust/session.rs +124 -117
  130. package/src/rust/tasks/column_locator.rs +133 -0
  131. package/src/rust/{model → tasks}/columns_iter_set.rs +14 -23
  132. package/src/rust/{model → tasks}/edit_expression.rs +34 -10
  133. package/src/rust/{model → tasks}/eject.rs +2 -2
  134. package/src/rust/{model → tasks}/get_viewer_config.rs +0 -11
  135. package/src/rust/{model → tasks}/intersection_observer.rs +19 -3
  136. package/src/{less/containers/radio-list.less → rust/tasks/is_invalid_drop.rs} +21 -14
  137. package/src/rust/tasks/mod.rs +52 -0
  138. package/src/rust/{model → tasks}/plugin_column_styles.rs +69 -46
  139. package/src/rust/{model → tasks}/resize_observer.rs +39 -6
  140. package/src/rust/{model → tasks}/send_plugin_config.rs +1 -1
  141. package/src/rust/tasks/structural.rs +53 -0
  142. package/src/rust/utils/mod.rs +4 -0
  143. package/src/rust/utils/modal_position.rs +110 -0
  144. package/src/rust/utils/ptr_eq_rc.rs +74 -0
  145. package/src/rust/utils/pubsub.rs +11 -1
  146. package/src/svg/bg-pattern.png +0 -0
  147. package/src/svg/close-icon.svg +1 -1
  148. package/src/svg/expression.svg +1 -1
  149. package/src/svg/mega-menu-icons-candlestick.svg +1 -1
  150. package/src/svg/mega-menu-icons-datagrid.svg +1 -2
  151. package/src/svg/mega-menu-icons-heatmap.svg +1 -1
  152. package/src/svg/mega-menu-icons-map-scatter.svg +1 -1
  153. package/src/svg/mega-menu-icons-ohlc.svg +1 -1
  154. package/src/svg/mega-menu-icons-sunburst.svg +1 -1
  155. package/src/svg/mega-menu-icons-treemap.svg +1 -1
  156. package/src/svg/mega-menu-icons-x-bar.svg +1 -1
  157. package/src/svg/mega-menu-icons-x-y-line.svg +1 -1
  158. package/src/svg/mega-menu-icons-x-y-scatter.svg +1 -1
  159. package/src/svg/mega-menu-icons-y-area.svg +1 -1
  160. package/src/svg/mega-menu-icons-y-bar.svg +1 -1
  161. package/src/svg/mega-menu-icons-y-line.svg +1 -1
  162. package/src/svg/mega-menu-icons-y-scatter.svg +1 -1
  163. package/src/svg/radio-hover.svg +1 -1
  164. package/src/svg/radio-off.svg +1 -1
  165. package/src/svg/radio-on.svg +1 -1
  166. package/src/themes/botanical.css +157 -0
  167. package/src/themes/defaults.css +139 -0
  168. package/src/themes/dracula.css +233 -0
  169. package/src/themes/gruvbox-dark.css +255 -0
  170. package/src/themes/gruvbox.css +134 -0
  171. package/src/themes/icons.css +124 -0
  172. package/src/themes/intl/de.css +102 -0
  173. package/src/themes/intl/es.css +102 -0
  174. package/src/themes/intl/fr.css +102 -0
  175. package/src/themes/intl/ja.css +102 -0
  176. package/src/themes/intl/pt.css +102 -0
  177. package/src/themes/intl/zh.css +102 -0
  178. package/src/themes/intl.css +102 -0
  179. package/src/themes/monokai.css +233 -0
  180. package/src/themes/pro-dark.css +158 -0
  181. package/src/themes/{themes.less → pro.css} +17 -21
  182. package/src/themes/solarized-dark.css +135 -0
  183. package/src/themes/solarized.css +95 -0
  184. package/src/themes/themes.css +22 -0
  185. package/src/themes/vaporwave.css +256 -0
  186. package/dist/css/variables.css +0 -0
  187. package/src/less/column-dropdown.less +0 -95
  188. package/src/less/dom/checkbox.less +0 -100
  189. package/src/less/plugin-selector.less +0 -183
  190. package/src/less/type-icon.less +0 -68
  191. package/src/rust/components/error_message.rs +0 -56
  192. package/src/rust/custom_elements/column_dropdown.rs +0 -123
  193. package/src/rust/custom_elements/filter_dropdown.rs +0 -179
  194. package/src/rust/custom_elements/function_dropdown.rs +0 -115
  195. package/src/rust/model/column_locator.rs +0 -82
  196. package/src/rust/model/is_invalid_drop.rs +0 -36
  197. package/src/rust/model/mod.rs +0 -100
  198. package/src/rust/model/reset_all.rs +0 -38
  199. package/src/rust/model/structural.rs +0 -244
  200. package/src/themes/botanical.less +0 -142
  201. package/src/themes/dracula.less +0 -101
  202. package/src/themes/gruvbox-dark.less +0 -116
  203. package/src/themes/gruvbox.less +0 -152
  204. package/src/themes/icons.less +0 -130
  205. package/src/themes/intl/de.less +0 -102
  206. package/src/themes/intl/es.less +0 -102
  207. package/src/themes/intl/fr.less +0 -102
  208. package/src/themes/intl/ja.less +0 -102
  209. package/src/themes/intl/pt.less +0 -102
  210. package/src/themes/intl/zh.less +0 -102
  211. package/src/themes/intl.less +0 -102
  212. package/src/themes/monokai.less +0 -107
  213. package/src/themes/pro-dark.less +0 -147
  214. package/src/themes/pro.less +0 -186
  215. package/src/themes/solarized-dark.less +0 -78
  216. package/src/themes/solarized.less +0 -102
  217. package/src/themes/vaporwave.less +0 -145
  218. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline0.js +0 -0
  219. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline1.js +0 -0
  220. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline2.js +0 -0
  221. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline3.js +0 -0
  222. /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline4.js +0 -0
  223. /package/src/rust/{model → tasks}/copy_export.rs +0 -0
  224. /package/src/rust/{model → tasks}/export_app.rs +0 -0
  225. /package/src/rust/{model → tasks}/export_method.rs +0 -0
  226. /package/src/rust/{model → tasks}/restore_and_render.rs +0 -0
  227. /package/src/rust/{model → tasks}/update_and_render.rs +0 -0
@@ -13,24 +13,91 @@
13
13
  use std::cell::RefCell;
14
14
  use std::rc::Rc;
15
15
 
16
- use ::perspective_js::utils::{global, *};
16
+ use perspective_js::utils::global;
17
17
  use wasm_bindgen::prelude::*;
18
18
  use wasm_bindgen_futures::spawn_local;
19
19
  use web_sys::*;
20
- use yew::*;
20
+ use yew::prelude::*;
21
21
 
22
- use super::modal::*;
23
22
  use super::viewer::PerspectiveViewerElement;
24
- use crate::components::copy_dropdown::{CopyDropDownMenu, CopyDropDownMenuProps};
23
+ use crate::components::copy_dropdown::CopyDropDownMenu;
24
+ use crate::components::portal::PortalModal;
25
+ use crate::components::style::StyleProvider;
25
26
  use crate::js::*;
26
- use crate::model::*;
27
+ use crate::renderer::*;
28
+ use crate::tasks::*;
27
29
  use crate::utils::*;
30
+ use crate::*;
31
+
32
+ type TargetState = Rc<RefCell<Option<HtmlElement>>>;
33
+
34
+ #[derive(Properties, PartialEq)]
35
+ struct CopyDropDownWrapperProps {
36
+ renderer: Renderer,
37
+ callback: Callback<ExportFile>,
38
+ target: TargetState,
39
+ custom_element: HtmlElement,
40
+ #[prop_or_default]
41
+ theme: String,
42
+ }
43
+
44
+ enum CopyDropDownWrapperMsg {
45
+ Open,
46
+ Close,
47
+ }
48
+
49
+ struct CopyDropDownWrapper {
50
+ target: Option<HtmlElement>,
51
+ }
52
+
53
+ impl Component for CopyDropDownWrapper {
54
+ type Message = CopyDropDownWrapperMsg;
55
+ type Properties = CopyDropDownWrapperProps;
56
+
57
+ fn create(_ctx: &Context<Self>) -> Self {
58
+ Self { target: None }
59
+ }
60
+
61
+ fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
62
+ match msg {
63
+ CopyDropDownWrapperMsg::Open => {
64
+ self.target = ctx.props().target.borrow().clone();
65
+ true
66
+ },
67
+ CopyDropDownWrapperMsg::Close => {
68
+ self.target = None;
69
+ true
70
+ },
71
+ }
72
+ }
73
+
74
+ fn view(&self, ctx: &Context<Self>) -> Html {
75
+ let on_close = ctx.link().callback(|_| CopyDropDownWrapperMsg::Close);
76
+ html! {
77
+ <StyleProvider root={ctx.props().custom_element.clone()}>
78
+ <PortalModal
79
+ tag_name="perspective-copy-menu"
80
+ target={self.target.clone()}
81
+ own_focus=true
82
+ {on_close}
83
+ theme={ctx.props().theme.clone()}
84
+ >
85
+ <CopyDropDownMenu
86
+ renderer={ctx.props().renderer.clone()}
87
+ callback={ctx.props().callback.clone()}
88
+ />
89
+ </PortalModal>
90
+ </StyleProvider>
91
+ }
92
+ }
93
+ }
28
94
 
29
95
  #[wasm_bindgen]
30
96
  #[derive(Clone)]
31
97
  pub struct CopyDropDownMenuElement {
32
98
  elem: HtmlElement,
33
- modal: Rc<RefCell<Option<ModalElement<CopyDropDownMenu>>>>,
99
+ target: TargetState,
100
+ root: Rc<RefCell<Option<AppHandle<CopyDropDownWrapper>>>>,
34
101
  }
35
102
 
36
103
  impl CustomElementMetadata for CopyDropDownMenuElement {
@@ -43,24 +110,25 @@ impl CopyDropDownMenuElement {
43
110
  pub fn new(elem: HtmlElement) -> Self {
44
111
  Self {
45
112
  elem,
46
- modal: Default::default(),
113
+ target: Default::default(),
114
+ root: Default::default(),
47
115
  }
48
116
  }
49
117
 
50
118
  pub fn open(&self, target: HtmlElement) {
51
- if let Some(x) = &*self.modal.borrow() {
52
- ApiFuture::spawn(x.clone().open(target, None));
119
+ *self.target.borrow_mut() = Some(target);
120
+ if let Some(root) = self.root.borrow().as_ref() {
121
+ root.send_message(CopyDropDownWrapperMsg::Open);
53
122
  }
54
123
  }
55
124
 
56
125
  pub fn hide(&self) -> ApiResult<()> {
57
- let borrowed = self.modal.borrow();
58
- borrowed.as_ref().into_apierror()?.hide()
126
+ if let Some(root) = self.root.borrow().as_ref() {
127
+ root.send_message(CopyDropDownWrapperMsg::Close);
128
+ }
129
+ Ok(())
59
130
  }
60
131
 
61
- /// Internal Only.
62
- ///
63
- /// Set this custom element model's raw pointer.
64
132
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
65
133
  self.set_config_model(parent)
66
134
  }
@@ -91,30 +159,43 @@ impl CopyDropDownMenuElement {
91
159
  {
92
160
  let callback = Callback::from({
93
161
  let model = model.clone_state();
94
- let modal_rc = self.modal.clone();
162
+ let target = self.target.clone();
163
+ let root = self.root.clone();
95
164
  move |x: ExportFile| {
96
165
  let model = model.clone();
97
- let modal = modal_rc.borrow().clone().unwrap();
166
+ let target = target.clone();
167
+ let root = root.clone();
98
168
  spawn_local(async move {
99
169
  let mime = x.method.mimetype(x.is_chart);
100
170
  let task = model.export_method_to_blob(x.method);
101
171
  let result = copy_to_clipboard(task, mime).await;
102
172
  crate::maybe_log!({
103
173
  result?;
104
- modal.hide()?;
174
+ *target.borrow_mut() = None;
175
+ if let Some(root) = root.borrow().as_ref() {
176
+ root.send_message(CopyDropDownWrapperMsg::Close);
177
+ }
105
178
  })
106
179
  })
107
180
  }
108
181
  });
109
182
 
110
183
  let renderer = model.renderer().clone();
111
- let props = props!(CopyDropDownMenuProps {
184
+ let init = ShadowRootInit::new(ShadowRootMode::Open);
185
+ let shadow_root = self
186
+ .elem
187
+ .attach_shadow(&init)
188
+ .unwrap()
189
+ .unchecked_into::<Element>();
190
+
191
+ let props = yew::props!(CopyDropDownWrapperProps {
112
192
  renderer,
113
193
  callback,
114
- root: self.elem.clone()
194
+ target: self.target.clone(),
195
+ custom_element: self.elem.clone()
115
196
  });
116
197
 
117
- let modal = ModalElement::new(self.elem.clone(), props, true, None);
118
- *self.modal.borrow_mut() = Some(modal);
198
+ let handle = yew::Renderer::with_root_and_props(shadow_root, props).render();
199
+ *self.root.borrow_mut() = Some(handle);
119
200
  }
120
201
  }
@@ -17,20 +17,89 @@ use perspective_js::utils::global;
17
17
  use wasm_bindgen::prelude::*;
18
18
  use wasm_bindgen_futures::spawn_local;
19
19
  use web_sys::*;
20
- use yew::*;
20
+ use yew::prelude::*;
21
21
 
22
22
  use super::viewer::PerspectiveViewerElement;
23
- use crate::components::export_dropdown::*;
24
- use crate::custom_elements::modal::*;
25
- use crate::model::*;
23
+ use crate::components::export_dropdown::ExportDropDownMenu;
24
+ use crate::components::portal::PortalModal;
25
+ use crate::components::style::StyleProvider;
26
+ use crate::renderer::*;
27
+ use crate::session::*;
28
+ use crate::tasks::*;
26
29
  use crate::utils::*;
27
30
  use crate::*;
28
31
 
32
+ type TargetState = Rc<RefCell<Option<HtmlElement>>>;
33
+
34
+ #[derive(Properties, PartialEq)]
35
+ struct ExportDropDownWrapperProps {
36
+ renderer: Renderer,
37
+ session: Session,
38
+ callback: Callback<ExportFile>,
39
+ target: TargetState,
40
+ custom_element: HtmlElement,
41
+ #[prop_or_default]
42
+ theme: String,
43
+ }
44
+
45
+ enum ExportDropDownWrapperMsg {
46
+ Open,
47
+ Close,
48
+ }
49
+
50
+ struct ExportDropDownWrapper {
51
+ target: Option<HtmlElement>,
52
+ }
53
+
54
+ impl Component for ExportDropDownWrapper {
55
+ type Message = ExportDropDownWrapperMsg;
56
+ type Properties = ExportDropDownWrapperProps;
57
+
58
+ fn create(_ctx: &Context<Self>) -> Self {
59
+ Self { target: None }
60
+ }
61
+
62
+ fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
63
+ match msg {
64
+ ExportDropDownWrapperMsg::Open => {
65
+ self.target = ctx.props().target.borrow().clone();
66
+ true
67
+ },
68
+ ExportDropDownWrapperMsg::Close => {
69
+ self.target = None;
70
+ true
71
+ },
72
+ }
73
+ }
74
+
75
+ fn view(&self, ctx: &Context<Self>) -> Html {
76
+ let on_close = ctx.link().callback(|_| ExportDropDownWrapperMsg::Close);
77
+ html! {
78
+ <StyleProvider root={ctx.props().custom_element.clone()}>
79
+ <PortalModal
80
+ tag_name="perspective-export-menu"
81
+ target={self.target.clone()}
82
+ own_focus=true
83
+ {on_close}
84
+ theme={ctx.props().theme.clone()}
85
+ >
86
+ <ExportDropDownMenu
87
+ renderer={ctx.props().renderer.clone()}
88
+ session={ctx.props().session.clone()}
89
+ callback={ctx.props().callback.clone()}
90
+ />
91
+ </PortalModal>
92
+ </StyleProvider>
93
+ }
94
+ }
95
+ }
96
+
29
97
  #[wasm_bindgen]
30
98
  #[derive(Clone)]
31
99
  pub struct ExportDropDownMenuElement {
32
100
  elem: HtmlElement,
33
- modal: Rc<RefCell<Option<ModalElement<ExportDropDownMenu>>>>,
101
+ target: TargetState,
102
+ root: Rc<RefCell<Option<AppHandle<ExportDropDownWrapper>>>>,
34
103
  }
35
104
 
36
105
  impl CustomElementMetadata for ExportDropDownMenuElement {
@@ -43,24 +112,25 @@ impl ExportDropDownMenuElement {
43
112
  pub fn new(elem: HtmlElement) -> Self {
44
113
  Self {
45
114
  elem,
46
- modal: Default::default(),
115
+ target: Default::default(),
116
+ root: Default::default(),
47
117
  }
48
118
  }
49
119
 
50
120
  pub fn open(&self, target: HtmlElement) {
51
- if let Some(x) = &*self.modal.borrow() {
52
- ApiFuture::spawn(x.clone().open(target, None));
121
+ *self.target.borrow_mut() = Some(target);
122
+ if let Some(root) = self.root.borrow().as_ref() {
123
+ root.send_message(ExportDropDownWrapperMsg::Open);
53
124
  }
54
125
  }
55
126
 
56
127
  pub fn hide(&self) -> ApiResult<()> {
57
- let borrowed = self.modal.borrow();
58
- borrowed.as_ref().into_apierror()?.hide()
128
+ if let Some(root) = self.root.borrow().as_ref() {
129
+ root.send_message(ExportDropDownWrapperMsg::Close);
130
+ }
131
+ Ok(())
59
132
  }
60
133
 
61
- /// Internal Only.
62
- ///
63
- /// Set this custom element model's raw pointer.
64
134
  pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
65
135
  self.set_config_model(parent)
66
136
  }
@@ -91,15 +161,19 @@ impl ExportDropDownMenuElement {
91
161
  {
92
162
  let callback = Callback::from({
93
163
  let model = model.clone_state();
94
- let modal_rc = self.modal.clone();
164
+ let target = self.target.clone();
165
+ let root = self.root.clone();
95
166
  move |x: ExportFile| {
96
167
  if !x.name.is_empty() {
97
- clone!(modal_rc, model);
168
+ clone!(target, root, model);
98
169
  spawn_local(async move {
99
170
  let val = model.export_method_to_blob(x.method).await.unwrap();
100
171
  let is_chart = model.renderer().is_chart();
101
172
  download(&x.as_filename(is_chart), &val).unwrap();
102
- modal_rc.borrow().clone().unwrap().hide().unwrap();
173
+ *target.borrow_mut() = None;
174
+ if let Some(root) = root.borrow().as_ref() {
175
+ root.send_message(ExportDropDownWrapperMsg::Close);
176
+ }
103
177
  })
104
178
  }
105
179
  }
@@ -107,14 +181,22 @@ impl ExportDropDownMenuElement {
107
181
 
108
182
  let renderer = model.renderer().clone();
109
183
  let session = model.session().clone();
110
- let props = props!(ExportDropDownMenuProps {
184
+ let init = ShadowRootInit::new(ShadowRootMode::Open);
185
+ let shadow_root = self
186
+ .elem
187
+ .attach_shadow(&init)
188
+ .unwrap()
189
+ .unchecked_into::<Element>();
190
+
191
+ let props = yew::props!(ExportDropDownWrapperProps {
111
192
  renderer,
112
193
  session,
113
194
  callback,
114
- root: self.elem.clone()
195
+ target: self.target.clone(),
196
+ custom_element: self.elem.clone(),
115
197
  });
116
198
 
117
- let modal = ModalElement::new(self.elem.clone(), props, true, None);
118
- *self.modal.borrow_mut() = Some(modal);
199
+ let handle = yew::Renderer::with_root_and_props(shadow_root, props).render();
200
+ *self.root.borrow_mut() = Some(handle);
119
201
  }
120
202
  }
@@ -13,15 +13,8 @@
13
13
  //! Each file in `custom_elements` exports a single struct which will be the
14
14
  //! public [`wasm_bindgen`] API to a JavaScript Custom Element.
15
15
 
16
- mod column_dropdown;
17
16
  pub mod copy_dropdown;
18
17
  pub mod debug_plugin;
19
18
  pub mod export_dropdown;
20
- mod filter_dropdown;
21
- mod function_dropdown;
22
19
  pub mod modal;
23
20
  pub mod viewer;
24
-
25
- pub use self::column_dropdown::*;
26
- pub use self::filter_dropdown::*;
27
- pub use self::function_dropdown::*;
@@ -56,81 +56,6 @@ where
56
56
  on_blur: Option<Callback<()>>,
57
57
  }
58
58
 
59
- /// Anchor point enum, `ModalCornerTargetCorner`
60
- #[derive(Clone, Copy, Debug, Default)]
61
- enum ModalAnchor {
62
- BottomRightTopLeft,
63
- BottomRightBottomLeft,
64
- BottomRightTopRight,
65
- BottomLeftTopLeft,
66
- TopRightTopLeft,
67
- TopRightBottomRight,
68
-
69
- #[default]
70
- TopLeftBottomLeft,
71
- }
72
-
73
- impl ModalAnchor {
74
- const fn is_rev_vert(&self) -> bool {
75
- matches!(
76
- self,
77
- Self::BottomLeftTopLeft
78
- | Self::BottomRightBottomLeft
79
- | Self::BottomRightTopLeft
80
- | Self::BottomRightTopRight
81
- )
82
- }
83
- }
84
-
85
- /// Given the bounds of the target element as previous computed, as well as the
86
- /// browser's viewport and the bounds of the already-connected
87
- /// `<perspectuve-style-menu>` element itself, determine a new (top, left)
88
- /// coordinates that keeps the element on-screen.
89
- fn calc_relative_position(
90
- elem: &HtmlElement,
91
- _top: f64,
92
- left: f64,
93
- height: f64,
94
- width: f64,
95
- ) -> ModalAnchor {
96
- let window = global::window();
97
- let rect = elem.get_bounding_client_rect();
98
- let inner_width = window.inner_width().unwrap().as_f64().unwrap();
99
- let inner_height = window.inner_height().unwrap().as_f64().unwrap();
100
- let rect_top = rect.top();
101
- let rect_height = rect.height();
102
- let rect_width = rect.width();
103
- let rect_left = rect.left();
104
-
105
- let elem_over_y = inner_height < rect_top + rect_height;
106
- let elem_over_x = inner_width < rect_left + rect_width;
107
- let target_over_x = inner_width < rect_left + width;
108
- let target_over_y = inner_height < rect_top + height;
109
-
110
- // modal/target
111
- match (elem_over_y, elem_over_x, target_over_x, target_over_y) {
112
- (true, _, true, true) => ModalAnchor::BottomRightTopLeft,
113
- (true, _, true, false) => ModalAnchor::BottomRightBottomLeft,
114
- (true, true, false, _) => {
115
- if left + width - rect_width > 0.0 {
116
- ModalAnchor::BottomRightTopRight
117
- } else {
118
- ModalAnchor::BottomLeftTopLeft
119
- }
120
- },
121
- (true, false, false, _) => ModalAnchor::BottomLeftTopLeft,
122
- (false, true, true, _) => ModalAnchor::TopRightTopLeft,
123
- (false, true, false, _) => {
124
- if left + width - rect_width > 0.0 {
125
- ModalAnchor::TopRightBottomRight
126
- } else {
127
- ModalAnchor::TopLeftBottomLeft
128
- }
129
- },
130
- _ => ModalAnchor::TopLeftBottomLeft,
131
- }
132
- }
133
-
134
59
  impl<T> ModalElement<T>
135
60
  where
136
61
  T: Component,
@@ -172,31 +97,10 @@ where
172
97
  }
173
98
  }
174
99
 
175
- fn calc_anchor_position(&self, target: &HtmlElement) -> (f64, f64) {
176
- let elem = target.unchecked_ref::<HtmlElement>();
177
- let rect = elem.get_bounding_client_rect();
178
- let height = rect.height();
179
- let width = rect.width();
180
- let top = rect.top();
181
- let left = rect.left();
182
-
183
- let self_rect = self.custom_element.get_bounding_client_rect();
184
- let rect_height = self_rect.height();
185
- let rect_width = self_rect.width();
186
-
187
- match self.anchor.get() {
188
- ModalAnchor::BottomRightTopLeft => (top - rect_height, left - rect_width + 1.0),
189
- ModalAnchor::BottomRightBottomLeft => {
190
- (top - rect_height + height, left - rect_width + 1.0)
191
- },
192
- ModalAnchor::BottomRightTopRight => {
193
- (top - rect_height + 1.0, left + width - rect_width)
194
- },
195
- ModalAnchor::BottomLeftTopLeft => (top - rect_height + 1.0, left),
196
- ModalAnchor::TopRightTopLeft => (top, left - rect_width + 1.0),
197
- ModalAnchor::TopRightBottomRight => (top + height - 1.0, left + width - rect_width),
198
- ModalAnchor::TopLeftBottomLeft => ((top + height - 1.0), left),
199
- }
100
+ fn calc_anchor_pos(&self, target: &HtmlElement) -> (f64, f64) {
101
+ let target_rect = target.get_bounding_client_rect();
102
+ let modal_rect = self.custom_element.get_bounding_client_rect();
103
+ calc_anchor_position(self.anchor.get(), &target_rect, &modal_rect)
200
104
  }
201
105
 
202
106
  async fn open_within_viewport(&self, target: HtmlElement) -> ApiResult<()> {
@@ -229,7 +133,7 @@ where
229
133
  width,
230
134
  ));
231
135
 
232
- let (top, left) = self.calc_anchor_position(&target);
136
+ let (top, left) = self.calc_anchor_pos(&target);
233
137
  let msg = ModalMsg::SetPos {
234
138
  top,
235
139
  left,
@@ -310,7 +214,7 @@ where
310
214
  let target = target.clone();
311
215
  let anchor = self.anchor.clone();
312
216
  *self.resize_sub.borrow_mut() = Some(resize.add_listener(move |()| {
313
- let (top, left) = this.calc_anchor_position(&target);
217
+ let (top, left) = this.calc_anchor_pos(&target);
314
218
  let msg = ModalMsg::SetPos {
315
219
  top,
316
220
  left,
@@ -382,7 +286,7 @@ where
382
286
  fn get_theme(elem: &HtmlElement) -> Option<String> {
383
287
  let styles = global::window().get_computed_style(elem).unwrap().unwrap();
384
288
  styles
385
- .get_property_value("--theme-name")
289
+ .get_property_value("--psp-theme-name")
386
290
  .ok()
387
291
  .and_then(|x| {
388
292
  let trimmed = x.trim();