@perspective-dev/viewer 4.0.0 → 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.
Files changed (184) 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/dracula.css +1 -1
  4. package/dist/css/gruvbox-dark.css +1 -1
  5. package/dist/css/gruvbox.css +1 -1
  6. package/dist/css/icons.css +1 -1
  7. package/dist/css/monokai.css +1 -1
  8. package/dist/css/pro-dark.css +1 -1
  9. package/dist/css/pro.css +1 -1
  10. package/dist/css/solarized-dark.css +1 -1
  11. package/dist/css/solarized.css +1 -1
  12. package/dist/css/themes.css +1 -1
  13. package/dist/css/vaporwave.css +1 -1
  14. package/dist/esm/extensions.d.ts +23 -2
  15. package/dist/esm/perspective-viewer.d.ts +2 -7
  16. package/dist/esm/perspective-viewer.inline.js +2 -2
  17. package/dist/esm/perspective-viewer.inline.js.map +4 -4
  18. package/dist/esm/perspective-viewer.js +2 -2
  19. package/dist/esm/perspective-viewer.js.map +4 -4
  20. package/dist/esm/plugin.d.ts +1 -1
  21. package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +1 -0
  22. package/dist/wasm/perspective-viewer.d.ts +218 -46
  23. package/dist/wasm/perspective-viewer.js +1251 -762
  24. package/dist/wasm/perspective-viewer.wasm +0 -0
  25. package/dist/wasm/perspective-viewer.wasm.d.ts +38 -19
  26. package/package.json +1 -1
  27. package/src/less/containers/scroll-panel.less +0 -1
  28. package/src/less/plugin-selector.less +15 -5
  29. package/src/less/status-bar.less +75 -27
  30. package/src/less/viewer.less +140 -58
  31. package/src/rust/components/column_dropdown.rs +21 -21
  32. package/src/rust/components/column_selector/active_column.rs +131 -120
  33. package/src/rust/components/column_selector/add_expression_button.rs +5 -0
  34. package/src/rust/components/column_selector/aggregate_selector.rs +8 -4
  35. package/src/rust/components/column_selector/config_selector.rs +170 -161
  36. package/src/rust/components/column_selector/empty_column.rs +16 -11
  37. package/src/rust/components/column_selector/{expression_toolbar.rs → expr_edit_button.rs} +7 -0
  38. package/src/rust/components/column_selector/filter_column.rs +195 -194
  39. package/src/rust/components/column_selector/inactive_column.rs +82 -67
  40. package/src/rust/components/column_selector/pivot_column.rs +16 -11
  41. package/src/rust/components/column_selector/sort_column.rs +9 -7
  42. package/src/rust/components/column_selector.rs +42 -37
  43. package/src/rust/components/column_settings_sidebar/save_settings.rs +3 -1
  44. package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +58 -0
  45. package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +6 -6
  46. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +2 -94
  47. package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +111 -0
  48. package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +3 -3
  49. package/src/rust/components/column_settings_sidebar/style_tab.rs +23 -83
  50. package/src/rust/components/{column_settings_sidebar/sidebar.rs → column_settings_sidebar.rs} +198 -171
  51. package/src/rust/components/containers/dragdrop_list.rs +20 -20
  52. package/src/rust/components/containers/dropdown_menu.rs +4 -6
  53. package/src/rust/components/containers/mod.rs +1 -4
  54. package/src/rust/components/containers/scroll_panel.rs +80 -80
  55. package/src/rust/components/containers/scroll_panel_item.rs +36 -36
  56. package/src/rust/components/containers/select.rs +46 -44
  57. package/src/rust/components/containers/sidebar.rs +3 -19
  58. package/src/rust/components/{column_settings_sidebar/style_tab/symbol/symbol_config.rs → containers/sidebar_close_button.rs} +15 -9
  59. package/src/rust/components/containers/split_panel.rs +212 -200
  60. package/src/rust/components/containers/tab_list.rs +11 -11
  61. package/src/rust/components/copy_dropdown.rs +22 -25
  62. package/src/rust/components/datetime_column_style/custom.rs +19 -19
  63. package/src/rust/components/datetime_column_style/simple.rs +13 -14
  64. package/src/rust/components/datetime_column_style.rs +75 -76
  65. package/src/rust/components/editable_header.rs +18 -14
  66. package/src/rust/components/empty_row.rs +5 -5
  67. package/src/rust/components/export_dropdown.rs +42 -42
  68. package/src/rust/components/expression_editor.rs +25 -19
  69. package/src/rust/components/filter_dropdown.rs +22 -22
  70. package/src/rust/components/font_loader.rs +11 -9
  71. package/src/rust/components/form/code_editor.rs +106 -105
  72. package/src/rust/components/form/color_range_selector.rs +14 -12
  73. package/src/rust/components/form/color_selector.rs +3 -1
  74. package/src/rust/components/form/debug.rs +95 -94
  75. package/src/rust/components/form/highlight.rs +5 -3
  76. package/src/rust/components/form/mod.rs +3 -2
  77. package/src/rust/components/form/optional_field.rs +2 -2
  78. package/src/rust/components/form/{select_field.rs → select_enum_field.rs} +1 -46
  79. package/src/rust/components/form/select_value_field.rs +64 -0
  80. package/src/rust/components/function_dropdown.rs +21 -21
  81. package/src/rust/components/main_panel.rs +219 -0
  82. package/src/rust/components/mod.rs +6 -6
  83. package/src/rust/components/modal.rs +42 -42
  84. package/src/rust/components/number_column_style.rs +34 -88
  85. package/src/rust/components/plugin_selector.rs +22 -25
  86. package/src/rust/components/render_warning.rs +9 -6
  87. package/src/rust/components/settings_panel.rs +82 -0
  88. package/src/rust/components/status_bar.rs +250 -146
  89. package/src/rust/components/status_bar_counter.rs +26 -119
  90. package/src/rust/components/status_indicator.rs +95 -79
  91. package/src/rust/components/string_column_style.rs +45 -45
  92. package/src/rust/components/style/style_provider.rs +1 -15
  93. package/src/rust/components/style_controls/number_string_format/digits_section.rs +1 -1
  94. package/src/rust/components/style_controls/number_string_format/misc_section.rs +1 -1
  95. package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -1
  96. package/src/rust/components/style_controls/number_string_format.rs +45 -46
  97. package/src/rust/components/type_icon.rs +14 -11
  98. package/src/rust/components/viewer.rs +241 -384
  99. package/src/rust/config/columns_config.rs +2 -2
  100. package/src/rust/config/datetime_column_style.rs +1 -6
  101. package/src/rust/config/mod.rs +1 -0
  102. package/src/rust/config/number_column_style.rs +0 -6
  103. package/src/rust/config/number_string_format.rs +27 -4
  104. package/src/rust/config/viewer_config.rs +27 -167
  105. package/src/rust/custom_elements/copy_dropdown.rs +14 -6
  106. package/src/rust/custom_elements/export_dropdown.rs +15 -7
  107. package/src/rust/custom_elements/filter_dropdown.rs +4 -4
  108. package/src/rust/custom_elements/mod.rs +3 -0
  109. package/src/rust/custom_elements/viewer.rs +353 -161
  110. package/src/rust/custom_events.rs +55 -32
  111. package/src/rust/dragdrop.rs +4 -24
  112. package/src/rust/exprtk/cursor.rs +10 -1
  113. package/src/rust/exprtk/mod.rs +2 -0
  114. package/src/rust/exprtk/tokenize.rs +20 -3
  115. package/src/rust/js/clipboard.rs +2 -2
  116. package/src/rust/js/mimetype.rs +2 -7
  117. package/src/rust/js/mod.rs +0 -1
  118. package/src/rust/js/plugin.rs +7 -0
  119. package/src/rust/lib.rs +18 -5
  120. package/src/rust/model/column_locator.rs +82 -0
  121. package/src/rust/model/columns_iter_set.rs +1 -0
  122. package/src/rust/model/copy_export.rs +50 -14
  123. package/src/rust/model/edit_expression.rs +2 -5
  124. package/src/rust/model/eject.rs +41 -0
  125. package/src/rust/model/export_app.rs +3 -2
  126. package/src/rust/model/get_viewer_config.rs +4 -28
  127. package/src/rust/model/intersection_observer.rs +20 -8
  128. package/src/rust/model/mod.rs +11 -4
  129. package/src/rust/model/plugin_column_styles.rs +0 -31
  130. package/src/rust/model/reset_all.rs +38 -0
  131. package/src/rust/model/resize_observer.rs +34 -7
  132. package/src/rust/model/restore_and_render.rs +12 -7
  133. package/src/rust/{utils/scope.rs → model/send_plugin_config.rs} +32 -35
  134. package/src/rust/model/structural.rs +194 -23
  135. package/src/rust/model/update_and_render.rs +14 -4
  136. package/src/rust/{model/create_col.rs → presentation/column_locator.rs} +73 -42
  137. package/src/rust/{utils/wasm_abi.rs → presentation/sheets.rs} +54 -40
  138. package/src/rust/presentation.rs +60 -119
  139. package/src/rust/renderer/activate.rs +20 -5
  140. package/src/rust/renderer/limits.rs +0 -149
  141. package/src/rust/renderer/render_timer.rs +1 -1
  142. package/src/rust/renderer.rs +34 -18
  143. package/src/rust/root.rs +50 -0
  144. package/src/rust/session/column_defaults_update.rs +4 -4
  145. package/src/rust/session/drag_drop_update.rs +1 -1
  146. package/src/rust/session/metadata.rs +3 -17
  147. package/src/rust/session/replace_expression_update.rs +1 -2
  148. package/src/rust/session.rs +162 -82
  149. package/src/rust/utils/browser/blob.rs +16 -2
  150. package/src/rust/utils/browser/download.rs +1 -0
  151. package/src/rust/{components/column_settings_sidebar/mod.rs → utils/browser/dragdrop.rs} +14 -5
  152. package/src/rust/utils/browser/mod.rs +8 -4
  153. package/src/rust/utils/browser/selection.rs +5 -0
  154. package/src/rust/utils/custom_element.rs +28 -13
  155. package/src/rust/utils/datetime.rs +5 -0
  156. package/src/rust/utils/debounce.rs +7 -1
  157. package/src/rust/utils/hooks/use_async_callback.rs +7 -17
  158. package/src/rust/utils/mod.rs +28 -40
  159. package/src/rust/utils/number_format.rs +6 -5
  160. package/src/rust/utils/pubsub.rs +15 -10
  161. package/src/rust/utils/weak_scope.rs +11 -1
  162. package/src/svg/bookmark-icon.svg +4 -0
  163. package/src/svg/drag-handle copy.svg +10 -0
  164. package/src/svg/drawer-tab-hover.svg +5 -7
  165. package/src/svg/drawer-tab-invert-hover.svg +4 -8
  166. package/src/svg/drawer-tab-invert.svg +4 -7
  167. package/src/svg/drawer-tab.svg +4 -6
  168. package/src/svg/status_ok.svg +24 -24
  169. package/src/ts/extensions.ts +51 -3
  170. package/src/ts/perspective-viewer.ts +2 -14
  171. package/src/ts/plugin.ts +1 -1
  172. package/src/ts/ts-rs/ViewerConfigUpdate.ts +1 -1
  173. package/src/rust/components/column_settings_sidebar/style_tab/column_style.rs +0 -177
  174. package/src/rust/components/containers/tests/mod.rs +0 -11
  175. package/src/rust/components/containers/tests/split_panel.rs +0 -91
  176. package/src/rust/js/testing.rs +0 -149
  177. package/src/rust/utils/tee.rs +0 -88
  178. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline0.js +0 -0
  179. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline1.js +0 -0
  180. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline2.js +0 -0
  181. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline3.js +0 -0
  182. /package/dist/wasm/snippets/{perspective-viewer-c69283f6f62a5f14 → perspective-viewer-0d326a25c1022412}/inline4.js +0 -0
  183. /package/src/rust/components/{style_controls.rs → style_controls/mod.rs} +0 -0
  184. /package/src/rust/{components/containers → config}/kvpair.rs +0 -0
@@ -12,7 +12,7 @@
12
12
 
13
13
  use std::cmp::max;
14
14
 
15
- use perspective_js::utils::global;
15
+ use perspective_js::utils::{ApiResult, global};
16
16
  use wasm_bindgen::JsCast;
17
17
  use wasm_bindgen::prelude::*;
18
18
  use web_sys::HtmlElement;
@@ -20,173 +20,7 @@ use yew::html::Scope;
20
20
  use yew::prelude::*;
21
21
 
22
22
  use crate::components::style::LocalStyle;
23
- #[cfg(test)]
24
- use crate::utils::*;
25
- use crate::*;
26
-
27
- /// The state for the `Resizing` action, including the `MouseEvent` callbacks
28
- /// and panel starting dimensions.
29
- struct ResizingState {
30
- mousemove: Closure<dyn Fn(MouseEvent)>,
31
- mouseup: Closure<dyn Fn(MouseEvent)>,
32
- cursor: String,
33
- index: usize,
34
- start: i32,
35
- total: i32,
36
- alt: i32,
37
- orientation: Orientation,
38
- reverse: bool,
39
- body_style: web_sys::CssStyleDeclaration,
40
- pointer_id: i32,
41
- pointer_elem: HtmlElement,
42
- }
43
-
44
- impl Drop for ResizingState {
45
- /// On `drop`, we must remove these event listeners from the document
46
- /// `body`. Without this, the `Closure` objects would not leak, but the
47
- /// document will continue to call them, causing runtime exceptions.
48
- fn drop(&mut self) {
49
- let result: ApiResult<()> = maybe! {
50
- let mousemove = self.mousemove.as_ref().unchecked_ref();
51
- global::body().remove_event_listener_with_callback("mousemove", mousemove)?;
52
- let mouseup = self.mouseup.as_ref().unchecked_ref();
53
- global::body().remove_event_listener_with_callback("mouseup", mouseup)?;
54
- self.release_cursor()?;
55
- Ok(())
56
- };
57
-
58
- result.expect("Drop failed")
59
- }
60
- }
61
-
62
- /// The minimum size a split panel child can be, including when overridden via
63
- /// user drag/drop.
64
- const MINIMUM_SIZE: i32 = 8;
65
-
66
- /// When the instantiated, capture the initial dimensions and create the
67
- /// MouseEvent callbacks.
68
- impl ResizingState {
69
- pub fn new(
70
- index: usize,
71
- client_offset: i32,
72
- ctx: &Context<SplitPanel>,
73
- first_elem: &HtmlElement,
74
- pointer_id: i32,
75
- pointer_elem: HtmlElement,
76
- ) -> ApiResult<Self> {
77
- let orientation = ctx.props().orientation;
78
- let reverse = ctx.props().reverse;
79
- let split_panel = ctx.link();
80
- let total = match orientation {
81
- Orientation::Horizontal => first_elem.offset_width(),
82
- Orientation::Vertical => first_elem.offset_height(),
83
- };
84
-
85
- let alt = match orientation {
86
- Orientation::Horizontal => first_elem.offset_height(),
87
- Orientation::Vertical => first_elem.offset_width(),
88
- };
89
-
90
- let mouseup = Closure::new({
91
- let cb = split_panel.callback(|_| SplitPanelMsg::StopResizing);
92
- move |x| cb.emit(x)
93
- });
94
-
95
- let mousemove = Closure::new({
96
- let cb = split_panel.callback(move |event: MouseEvent| {
97
- SplitPanelMsg::MoveResizing(match orientation {
98
- Orientation::Horizontal => event.client_x(),
99
- Orientation::Vertical => event.client_y(),
100
- })
101
- });
102
- move |x| cb.emit(x)
103
- });
104
-
105
- let mut state = Self {
106
- index,
107
- cursor: "".to_owned(),
108
- start: client_offset,
109
- orientation,
110
- reverse,
111
- total,
112
- alt,
113
- body_style: global::body().style(),
114
- mouseup,
115
- mousemove,
116
- pointer_id,
117
- pointer_elem,
118
- };
119
-
120
- state.capture_cursor()?;
121
- state.register_listeners()?;
122
- Ok(state)
123
- }
124
-
125
- fn get_offset(&self, client_offset: i32) -> i32 {
126
- let delta = if self.reverse {
127
- self.start - client_offset
128
- } else {
129
- client_offset - self.start
130
- };
131
-
132
- max(MINIMUM_SIZE, self.total + delta)
133
- }
134
-
135
- pub fn get_style(&self, client_offset: i32) -> Option<String> {
136
- let offset = self.get_offset(client_offset);
137
- Some(match self.orientation {
138
- Orientation::Horizontal => {
139
- format!("max-width:{offset}px;min-width:{offset}px;width:{offset}px")
140
- },
141
- Orientation::Vertical => {
142
- format!("max-height:{offset}px;min-height:{offset}px;height:{offset}px")
143
- },
144
- })
145
- }
146
-
147
- pub fn get_dimensions(&self, client_offset: i32) -> (i32, i32) {
148
- let offset = self.get_offset(client_offset);
149
- match self.orientation {
150
- Orientation::Horizontal => (std::cmp::max(MINIMUM_SIZE, offset), self.alt),
151
- Orientation::Vertical => (self.alt, std::cmp::max(MINIMUM_SIZE, offset)),
152
- }
153
- }
154
-
155
- /// Adds the event listeners, the corollary of `Drop`.
156
- fn register_listeners(&self) -> ApiResult<()> {
157
- let mousemove = self.mousemove.as_ref().unchecked_ref();
158
- global::body().add_event_listener_with_callback("mousemove", mousemove)?;
159
- let mouseup = self.mouseup.as_ref().unchecked_ref();
160
- Ok(global::body().add_event_listener_with_callback("mouseup", mouseup)?)
161
- }
162
-
163
- /// Helper functions capture and release the global cursor while dragging is
164
- /// occurring.
165
- fn capture_cursor(&mut self) -> ApiResult<()> {
166
- self.pointer_elem.set_pointer_capture(self.pointer_id)?;
167
- self.cursor = self.body_style.get_property_value("cursor")?;
168
- self.body_style
169
- .set_property("cursor", match self.orientation {
170
- Orientation::Horizontal => "col-resize",
171
- Orientation::Vertical => "row-resize",
172
- })?;
173
-
174
- Ok(())
175
- }
176
-
177
- /// " but for release
178
- fn release_cursor(&self) -> ApiResult<()> {
179
- self.pointer_elem.release_pointer_capture(self.pointer_id)?;
180
- Ok(self.body_style.set_property("cursor", &self.cursor)?)
181
- }
182
- }
183
-
184
- #[derive(Clone, Copy, Default, Eq, PartialEq)]
185
- pub enum Orientation {
186
- #[default]
187
- Horizontal,
188
- Vertical,
189
- }
23
+ use crate::{css, maybe};
190
24
 
191
25
  #[derive(Properties, Default)]
192
26
  pub struct SplitPanelProps {
@@ -220,10 +54,6 @@ pub struct SplitPanelProps {
220
54
  #[prop_or_default]
221
55
  pub on_resize_finished: Option<Callback<()>>,
222
56
 
223
- #[cfg(test)]
224
- #[prop_or_default]
225
- pub weak_link: WeakScope<SplitPanel>,
226
-
227
57
  #[prop_or_default]
228
58
  pub initial_size: Option<i32>,
229
59
  }
@@ -278,7 +108,6 @@ impl Component for SplitPanel {
278
108
 
279
109
  fn create(ctx: &Context<Self>) -> Self {
280
110
  assert!(ctx.props().validate());
281
- enable_weak_link_test!(ctx.props(), ctx.link());
282
111
  let len = ctx.props().children.len();
283
112
  // cant just use vec![Default::default(); len] as it would
284
113
  // use the same underlying NodeRef for each element.
@@ -351,7 +180,14 @@ impl Component for SplitPanel {
351
180
  }
352
181
 
353
182
  fn view(&self, ctx: &Context<Self>) -> Html {
354
- let mut iter = ctx.props().children.iter();
183
+ let iter = ctx
184
+ .props()
185
+ .children
186
+ .iter()
187
+ .filter(|x| !ctx.props().skip_empty || x != &html! { <></> })
188
+ .enumerate()
189
+ .collect::<Vec<_>>();
190
+
355
191
  let orientation = ctx.props().orientation;
356
192
  let mut classes = classes!("split-panel");
357
193
  if orientation == Orientation::Vertical {
@@ -362,38 +198,50 @@ impl Component for SplitPanel {
362
198
  classes.push("orient-reverse");
363
199
  }
364
200
 
365
- let head = iter.next().unwrap();
366
-
367
- let tail = iter
368
- .filter(|x| !ctx.props().skip_empty || x != &html! { <></> })
369
- .enumerate()
370
- .map(|(i, x)| {
371
- html! {
372
- <key={i + 2}>
373
- <SplitPanelDivider
374
- {i}
375
- orientation={ctx.props().orientation}
376
- link={ctx.link().clone()}
377
- />
378
- if i == ctx.props().children.len() - 2 { { x } } else {
201
+ let count = iter.len();
202
+ let contents = html! {
203
+ <>
204
+ <LocalStyle key=0 href={css!("containers/split-panel")} />
205
+ for (i, x) in iter {
206
+ if i == 0 {
207
+ if count == 1 {
208
+ <key={i}>
209
+ {x}
210
+ </>
211
+ } else {
379
212
  <SplitPanelChild
380
- style={self.styles[i + 1].clone()}
381
- ref_={self.refs[i + 1].clone()}
213
+ key=0
214
+ style={self.styles[i].clone()}
215
+ ref_={self.refs[i].clone()}
382
216
  >
383
217
  { x }
384
218
  </SplitPanelChild>
385
219
  }
386
- </>
220
+ } else if i == count - 1 {
221
+ <key={i}>
222
+ <SplitPanelDivider
223
+ i={i - 1}
224
+ orientation={ctx.props().orientation}
225
+ link={ctx.link().clone()}
226
+ />
227
+ { x }
228
+ </>
229
+ } else {
230
+ <key={i}>
231
+ <SplitPanelDivider
232
+ i={i - 1}
233
+ orientation={ctx.props().orientation}
234
+ link={ctx.link().clone()}
235
+ />
236
+ <SplitPanelChild
237
+ style={self.styles[i].clone()}
238
+ ref_={self.refs[i].clone()}
239
+ >
240
+ { x }
241
+ </SplitPanelChild>
242
+ </>
243
+ }
387
244
  }
388
- });
389
-
390
- let contents = html! {
391
- <>
392
- <LocalStyle key=0 href={css!("containers/split-panel")} />
393
- <SplitPanelChild key=1 style={self.styles[0].clone()} ref_={self.refs[0].clone()}>
394
- { head }
395
- </SplitPanelChild>
396
- { for tail }
397
245
  </>
398
246
  };
399
247
 
@@ -406,6 +254,13 @@ impl Component for SplitPanel {
406
254
  }
407
255
  }
408
256
 
257
+ #[derive(Clone, Copy, Default, Eq, PartialEq)]
258
+ pub enum Orientation {
259
+ #[default]
260
+ Horizontal,
261
+ Vertical,
262
+ }
263
+
409
264
  #[derive(Properties)]
410
265
  struct SplitPanelDividerProps {
411
266
  i: usize,
@@ -481,3 +336,160 @@ fn split_panel_child(props: &SplitPanelChildProps) -> Html {
481
336
  </div>
482
337
  }
483
338
  }
339
+
340
+ /// The state for the `Resizing` action, including the `MouseEvent` callbacks
341
+ /// and panel starting dimensions.
342
+ struct ResizingState {
343
+ mousemove: Closure<dyn Fn(MouseEvent)>,
344
+ mouseup: Closure<dyn Fn(MouseEvent)>,
345
+ cursor: String,
346
+ index: usize,
347
+ start: i32,
348
+ total: i32,
349
+ alt: i32,
350
+ orientation: Orientation,
351
+ reverse: bool,
352
+ body_style: web_sys::CssStyleDeclaration,
353
+ pointer_id: i32,
354
+ pointer_elem: HtmlElement,
355
+ }
356
+
357
+ impl Drop for ResizingState {
358
+ /// On `drop`, we must remove these event listeners from the document
359
+ /// `body`. Without this, the `Closure` objects would not leak, but the
360
+ /// document will continue to call them, causing runtime exceptions.
361
+ fn drop(&mut self) {
362
+ let result: ApiResult<()> = maybe! {
363
+ let mousemove = self.mousemove.as_ref().unchecked_ref();
364
+ global::body().remove_event_listener_with_callback("mousemove", mousemove)?;
365
+ let mouseup = self.mouseup.as_ref().unchecked_ref();
366
+ global::body().remove_event_listener_with_callback("mouseup", mouseup)?;
367
+ self.release_cursor()?;
368
+ Ok(())
369
+ };
370
+
371
+ result.expect("Drop failed")
372
+ }
373
+ }
374
+
375
+ /// The minimum size a split panel child can be, including when overridden via
376
+ /// user drag/drop.
377
+ const MINIMUM_SIZE: i32 = 8;
378
+
379
+ /// When the instantiated, capture the initial dimensions and create the
380
+ /// MouseEvent callbacks.
381
+ impl ResizingState {
382
+ pub fn new(
383
+ index: usize,
384
+ client_offset: i32,
385
+ ctx: &Context<SplitPanel>,
386
+ first_elem: &HtmlElement,
387
+ pointer_id: i32,
388
+ pointer_elem: HtmlElement,
389
+ ) -> ApiResult<Self> {
390
+ let orientation = ctx.props().orientation;
391
+ let reverse = ctx.props().reverse;
392
+ let split_panel = ctx.link();
393
+ let total = match orientation {
394
+ Orientation::Horizontal => first_elem.offset_width(),
395
+ Orientation::Vertical => first_elem.offset_height(),
396
+ };
397
+
398
+ let alt = match orientation {
399
+ Orientation::Horizontal => first_elem.offset_height(),
400
+ Orientation::Vertical => first_elem.offset_width(),
401
+ };
402
+
403
+ let mouseup = Closure::new({
404
+ let cb = split_panel.callback(|_| SplitPanelMsg::StopResizing);
405
+ move |x| cb.emit(x)
406
+ });
407
+
408
+ let mousemove = Closure::new({
409
+ let cb = split_panel.callback(move |event: MouseEvent| {
410
+ SplitPanelMsg::MoveResizing(match orientation {
411
+ Orientation::Horizontal => event.client_x(),
412
+ Orientation::Vertical => event.client_y(),
413
+ })
414
+ });
415
+ move |x| cb.emit(x)
416
+ });
417
+
418
+ let mut state = Self {
419
+ index,
420
+ cursor: "".to_owned(),
421
+ start: client_offset,
422
+ orientation,
423
+ reverse,
424
+ total,
425
+ alt,
426
+ body_style: global::body().style(),
427
+ mouseup,
428
+ mousemove,
429
+ pointer_id,
430
+ pointer_elem,
431
+ };
432
+
433
+ state.capture_cursor()?;
434
+ state.register_listeners()?;
435
+ Ok(state)
436
+ }
437
+
438
+ fn get_offset(&self, client_offset: i32) -> i32 {
439
+ let delta = if self.reverse {
440
+ self.start - client_offset
441
+ } else {
442
+ client_offset - self.start
443
+ };
444
+
445
+ max(MINIMUM_SIZE, self.total + delta)
446
+ }
447
+
448
+ pub fn get_style(&self, client_offset: i32) -> Option<String> {
449
+ let offset = self.get_offset(client_offset);
450
+ Some(match self.orientation {
451
+ Orientation::Horizontal => {
452
+ format!("max-width:{offset}px;min-width:{offset}px;width:{offset}px")
453
+ },
454
+ Orientation::Vertical => {
455
+ format!("max-height:{offset}px;min-height:{offset}px;height:{offset}px")
456
+ },
457
+ })
458
+ }
459
+
460
+ pub fn get_dimensions(&self, client_offset: i32) -> (i32, i32) {
461
+ let offset = self.get_offset(client_offset);
462
+ match self.orientation {
463
+ Orientation::Horizontal => (std::cmp::max(MINIMUM_SIZE, offset), self.alt),
464
+ Orientation::Vertical => (self.alt, std::cmp::max(MINIMUM_SIZE, offset)),
465
+ }
466
+ }
467
+
468
+ /// Adds the event listeners, the corollary of `Drop`.
469
+ fn register_listeners(&self) -> ApiResult<()> {
470
+ let mousemove = self.mousemove.as_ref().unchecked_ref();
471
+ global::body().add_event_listener_with_callback("mousemove", mousemove)?;
472
+ let mouseup = self.mouseup.as_ref().unchecked_ref();
473
+ Ok(global::body().add_event_listener_with_callback("mouseup", mouseup)?)
474
+ }
475
+
476
+ /// Helper functions capture and release the global cursor while dragging is
477
+ /// occurring.
478
+ fn capture_cursor(&mut self) -> ApiResult<()> {
479
+ self.pointer_elem.set_pointer_capture(self.pointer_id)?;
480
+ self.cursor = self.body_style.get_property_value("cursor")?;
481
+ self.body_style
482
+ .set_property("cursor", match self.orientation {
483
+ Orientation::Horizontal => "col-resize",
484
+ Orientation::Vertical => "row-resize",
485
+ })?;
486
+
487
+ Ok(())
488
+ }
489
+
490
+ /// " but for release
491
+ fn release_cursor(&self) -> ApiResult<()> {
492
+ self.pointer_elem.release_pointer_capture(self.pointer_id)?;
493
+ Ok(self.body_style.set_property("cursor", &self.cursor)?)
494
+ }
495
+ }
@@ -14,20 +14,20 @@ use yew::{Callback, Children, Component, Html, Properties, classes, html};
14
14
 
15
15
  use crate::components::style::LocalStyle;
16
16
  use crate::css;
17
-
18
- pub trait Tab: PartialEq + std::fmt::Display + Clone + Default + 'static {}
19
-
20
- impl Tab for String {}
21
-
22
- impl Tab for &'static str {}
17
+ use crate::presentation::ColumnTab;
23
18
 
24
19
  #[derive(Properties, Debug, PartialEq)]
25
- pub struct TabListProps<T: Tab> {
26
- // all possible tabs
20
+ pub struct TabListProps<T: ColumnTab> {
21
+ /// All tabs
27
22
  pub tabs: Vec<T>,
23
+
24
+ /// Fires when the selected tab changes in the UI.
28
25
  pub on_tab_change: Callback<(usize, T)>,
26
+
27
+ // Which tab is selected.
29
28
  pub selected_tab: Option<usize>,
30
- // the curently instantiated tabs
29
+
30
+ // The currently instantiated tabs.
31
31
  pub children: Children,
32
32
  }
33
33
 
@@ -35,12 +35,12 @@ pub enum TabListMsg {
35
35
  SetSelected(usize),
36
36
  }
37
37
 
38
- pub struct TabList<T: Tab> {
38
+ pub struct TabList<T: ColumnTab> {
39
39
  t: std::marker::PhantomData<T>,
40
40
  selected_idx: usize,
41
41
  }
42
42
 
43
- impl<T: Tab> Component for TabList<T> {
43
+ impl<T: ColumnTab> Component for TabList<T> {
44
44
  type Message = TabListMsg;
45
45
  type Properties = TabListProps<T>;
46
46
 
@@ -21,37 +21,49 @@ use crate::model::*;
21
21
  use crate::renderer::*;
22
22
  use crate::utils::*;
23
23
 
24
- pub type CopyDropDownMenuMsg = DropDownMenuMsg;
25
- pub type CopyDropDownMenuItem = DropDownMenuItem<ExportFile>;
24
+ type CopyDropDownMenuItem = DropDownMenuItem<ExportFile>;
26
25
 
27
26
  #[derive(Properties, PartialEq)]
28
27
  pub struct CopyDropDownMenuProps {
29
- pub renderer: Renderer,
30
28
  pub callback: Callback<ExportFile>,
31
29
  pub root: web_sys::HtmlElement,
30
+ pub renderer: Renderer,
32
31
 
33
32
  #[prop_or_default]
34
33
  weak_link: WeakScope<CopyDropDownMenu>,
35
34
  }
36
35
 
37
- pub struct CopyDropDownMenu {
38
- _sub: Subscription,
39
- }
40
-
41
36
  impl ModalLink<CopyDropDownMenu> for CopyDropDownMenuProps {
42
37
  fn weak_link(&self) -> &'_ WeakScope<CopyDropDownMenu> {
43
38
  &self.weak_link
44
39
  }
45
40
  }
46
41
 
42
+ pub struct CopyDropDownMenu {
43
+ _sub: Subscription,
44
+ }
45
+
47
46
  impl Component for CopyDropDownMenu {
48
- type Message = CopyDropDownMenuMsg;
47
+ type Message = ();
49
48
  type Properties = CopyDropDownMenuProps;
50
49
 
50
+ fn create(ctx: &Context<Self>) -> Self {
51
+ ctx.set_modal_link();
52
+ let _sub = ctx
53
+ .props()
54
+ .renderer
55
+ .plugin_changed
56
+ .add_listener(ctx.link().callback(|_| ()));
57
+
58
+ Self { _sub }
59
+ }
60
+
61
+ fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
62
+ true
63
+ }
64
+
51
65
  fn view(&self, ctx: &Context<Self>) -> yew::virtual_dom::VNode {
52
66
  let plugin = ctx.props().renderer.get_active_plugin().unwrap();
53
- // let has_render = js_sys::Reflect::has(&plugin,
54
- // js_intern::js_intern!("render")).unwrap();
55
67
  let is_chart = plugin.name().as_str() != "Datagrid";
56
68
  let has_selection = ctx.props().renderer.get_selection().is_some();
57
69
  html! {
@@ -63,21 +75,6 @@ impl Component for CopyDropDownMenu {
63
75
  </StyleProvider>
64
76
  }
65
77
  }
66
-
67
- fn update(&mut self, _ctx: &Context<Self>, _msg: Self::Message) -> bool {
68
- true
69
- }
70
-
71
- fn create(ctx: &Context<Self>) -> Self {
72
- ctx.set_modal_link();
73
- let _sub = ctx
74
- .props()
75
- .renderer
76
- .plugin_changed
77
- .add_listener(ctx.link().callback(|_| ()));
78
-
79
- Self { _sub }
80
- }
81
78
  }
82
79
 
83
80
  fn get_menu_items(is_chart: bool, has_selection: bool) -> Vec<CopyDropDownMenuItem> {
@@ -15,23 +15,11 @@ use std::rc::Rc;
15
15
  use yew::prelude::*;
16
16
 
17
17
  use crate::components::form::number_field::NumberField;
18
- use crate::components::form::select_field::SelectValueField;
18
+ use crate::components::form::select_value_field::SelectValueField;
19
19
  use crate::components::modal::{ModalLink, SetModalLink};
20
20
  use crate::config::*;
21
21
  use crate::utils::WeakScope;
22
22
 
23
- pub enum DatetimeStyleCustomMsg {
24
- FractionalSeconds(Option<f64>),
25
- Year(CustomDatetimeFormat),
26
- Month(CustomDatetimeFormat),
27
- Day(CustomDatetimeFormat),
28
- Weekday(CustomDatetimeFormat),
29
- Hour(CustomDatetimeFormat),
30
- Minute(CustomDatetimeFormat),
31
- Second(CustomDatetimeFormat),
32
- Hour12(bool),
33
- }
34
-
35
23
  #[derive(Properties)]
36
24
  pub struct DatetimeStyleCustomProps {
37
25
  pub enable_time_config: bool,
@@ -57,18 +45,24 @@ impl PartialEq for DatetimeStyleCustomProps {
57
45
  }
58
46
  }
59
47
 
48
+ pub enum DatetimeStyleCustomMsg {
49
+ FractionalSeconds(Option<f64>),
50
+ Year(CustomDatetimeFormat),
51
+ Month(CustomDatetimeFormat),
52
+ Day(CustomDatetimeFormat),
53
+ Weekday(CustomDatetimeFormat),
54
+ Hour(CustomDatetimeFormat),
55
+ Minute(CustomDatetimeFormat),
56
+ Second(CustomDatetimeFormat),
57
+ Hour12(bool),
58
+ }
59
+
60
60
  /// The custom variation of the options parameter for `Intl.DatetimeFormat`.
61
61
  /// Complement to `DatetimeStyleSimple`.
62
62
  pub struct DatetimeStyleCustom {
63
63
  config: CustomDatetimeStyleConfig,
64
64
  }
65
65
 
66
- impl DatetimeStyleCustom {
67
- fn dispatch_config(&self, ctx: &Context<Self>) {
68
- ctx.props().on_change.emit(self.config.clone());
69
- }
70
- }
71
-
72
66
  impl Component for DatetimeStyleCustom {
73
67
  type Message = DatetimeStyleCustomMsg;
74
68
  type Properties = DatetimeStyleCustomProps;
@@ -220,3 +214,9 @@ impl Component for DatetimeStyleCustom {
220
214
  }
221
215
  }
222
216
  }
217
+
218
+ impl DatetimeStyleCustom {
219
+ fn dispatch_config(&self, ctx: &Context<Self>) {
220
+ ctx.props().on_change.emit(self.config.clone());
221
+ }
222
+ }