@perspective-dev/viewer 4.5.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/perspective-viewer.js +20 -1
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/gruvbox-dark.css +1 -1
- package/dist/css/gruvbox.css +1 -1
- package/dist/css/icons.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/phosphor.css +1 -1
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/css/solarized-dark.css +1 -1
- package/dist/css/solarized.css +1 -1
- package/dist/css/themes.css +1 -1
- package/dist/css/vaporwave.css +1 -1
- package/dist/esm/extensions.d.ts +22 -3
- package/dist/esm/perspective-viewer.cdn.d.ts +3 -0
- package/dist/esm/perspective-viewer.d.ts +9 -0
- package/dist/esm/perspective-viewer.inline.d.ts +3 -0
- package/dist/esm/perspective-viewer.inline.js +20 -1
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +20 -1
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/plugin.d.ts +71 -5
- package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
- package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
- package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
- package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
- package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
- package/dist/esm/ts-rs/Layout.d.ts +11 -0
- package/dist/esm/ts-rs/OnUpdateData.d.ts +6 -0
- package/dist/esm/ts-rs/Orientation.d.ts +4 -0
- package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
- package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
- package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
- package/dist/esm/ts-rs/ViewOnUpdateResp.d.ts +4 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
- package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
- package/dist/wasm/perspective-viewer.d.ts +213 -79
- package/dist/wasm/perspective-viewer.js +537 -189
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +36 -28
- package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
- package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
- package/package.json +3 -2
- package/src/css/_column_dropdown.css +14 -0
- package/src/css/_context_menu.css +14 -0
- package/src/css/_dropdown_menu.css +14 -0
- package/src/css/_filter_dropdown.css +14 -0
- package/src/css/_function_dropdown.css +14 -0
- package/src/css/_viewer_bundle.css +41 -0
- package/src/css/column-settings-panel.css +1 -1
- package/src/css/containers/context-menu.css +101 -0
- package/src/css/panel-tab.css +193 -0
- package/src/css/plugin-selector.css +7 -10
- package/src/css/status-bar.css +75 -81
- package/src/css/viewer.css +181 -71
- package/src/rust/components/column_dropdown.rs +43 -33
- package/src/rust/components/column_selector/active_column.rs +7 -18
- package/src/rust/components/column_selector/aggregate_selector.rs +4 -10
- package/src/rust/components/column_selector/config_selector.rs +33 -84
- package/src/rust/components/column_selector/empty_column.rs +0 -3
- package/src/rust/components/column_selector/filter_column.rs +5 -18
- package/src/rust/components/column_selector/inactive_column.rs +3 -8
- package/src/rust/components/column_selector/invalid_column.rs +0 -4
- package/src/rust/components/column_selector/sort_column.rs +3 -6
- package/src/rust/components/column_selector.rs +5 -14
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +0 -3
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +0 -3
- package/src/rust/components/column_settings_sidebar.rs +0 -3
- package/src/rust/components/containers/dropdown_menu.rs +1 -3
- package/src/rust/components/containers/scroll_panel.rs +1 -3
- package/src/rust/components/containers/split_panel.rs +175 -66
- package/src/rust/components/containers/tab_list.rs +0 -3
- package/src/rust/components/context_menu.rs +130 -0
- package/src/rust/components/datetime_column_style.rs +0 -3
- package/src/rust/components/empty_row.rs +0 -3
- package/src/rust/components/expression_editor.rs +2 -3
- package/src/rust/components/filter_dropdown.rs +3 -3
- package/src/rust/components/font_loader.rs +2 -2
- package/src/rust/components/form/code_editor.rs +0 -3
- package/src/rust/components/form/debug.rs +3 -4
- package/src/rust/components/function_dropdown.rs +3 -3
- package/src/rust/components/global_filter_bar.rs +76 -0
- package/src/rust/components/main_panel/frame_theme.rs +186 -0
- package/src/rust/components/main_panel/msg.rs +62 -0
- package/src/rust/components/main_panel/presize.rs +220 -0
- package/src/rust/components/main_panel/reconcile.rs +224 -0
- package/src/rust/components/main_panel/render.rs +385 -0
- package/src/rust/components/main_panel/update.rs +184 -0
- package/src/rust/components/main_panel.rs +311 -71
- package/src/rust/components/mod.rs +4 -0
- package/src/rust/components/number_series_style.rs +0 -3
- package/src/rust/components/panel_menu.rs +486 -0
- package/src/rust/components/panel_tab.rs +505 -0
- package/src/rust/components/plugin_selector.rs +0 -3
- package/src/rust/components/plugin_tab.rs +1 -6
- package/src/rust/components/portal.rs +5 -2
- package/src/rust/components/render_warning.rs +0 -3
- package/src/rust/components/settings_panel.rs +13 -5
- package/src/rust/components/status_bar.rs +113 -180
- package/src/rust/components/status_indicator.rs +6 -9
- package/src/rust/components/string_column_style.rs +0 -3
- package/src/rust/components/style/mod.rs +65 -27
- package/src/rust/components/style/style_provider.rs +51 -16
- package/src/rust/components/style_controls/number_string_format.rs +1 -8
- package/src/rust/components/type_icon.rs +1 -4
- package/src/rust/components/viewer/filters.rs +133 -0
- package/src/rust/components/viewer/msg.rs +180 -0
- package/src/rust/components/viewer/panels.rs +326 -0
- package/src/rust/components/viewer/render.rs +243 -0
- package/src/rust/components/viewer/settings.rs +402 -0
- package/src/rust/components/viewer/snapshots.rs +134 -0
- package/src/rust/components/viewer/wiring.rs +505 -0
- package/src/rust/components/viewer.rs +243 -758
- package/src/rust/config/export_method.rs +1 -1
- package/src/rust/config/mod.rs +4 -0
- package/src/rust/config/options.rs +71 -0
- package/src/rust/config/viewer_config.rs +24 -2
- package/src/rust/config/workspace_config.rs +92 -0
- package/src/rust/custom_elements/copy_dropdown.rs +9 -3
- package/src/rust/custom_elements/debug_plugin.rs +20 -1
- package/src/rust/custom_elements/export_dropdown.rs +9 -3
- package/src/rust/custom_elements/viewer.rs +1015 -286
- package/src/rust/custom_events.rs +212 -61
- package/src/rust/js/mod.rs +2 -0
- package/src/rust/js/plugin.rs +297 -10
- package/src/rust/js/regular_layout.rs +258 -0
- package/src/rust/lib.rs +20 -2
- package/src/rust/presentation.rs +66 -33
- package/src/rust/queries/get_viewer_config.rs +29 -11
- package/src/rust/queries/plugin_column_styles.rs +2 -2
- package/src/rust/renderer/activate.rs +41 -14
- package/src/rust/renderer/dispatch.rs +436 -0
- package/src/rust/renderer/plugin_config.rs +495 -0
- package/src/rust/renderer/registry.rs +18 -6
- package/src/rust/renderer/render_timer.rs +29 -10
- package/src/rust/renderer.rs +350 -827
- package/src/rust/session/column_defaults_update.rs +26 -8
- package/src/rust/session/metadata.rs +11 -1
- package/src/rust/session/view_subscription.rs +30 -15
- package/src/rust/session.rs +753 -251
- package/src/rust/tasks/apply_global_filters.rs +89 -0
- package/src/rust/tasks/auto_pause.rs +171 -0
- package/src/rust/tasks/copy_export.rs +29 -19
- package/src/rust/tasks/create_panel.rs +243 -0
- package/src/rust/tasks/dismiss_render_warning.rs +3 -1
- package/src/rust/tasks/edit_expression.rs +4 -4
- package/src/rust/tasks/eject.rs +64 -23
- package/src/rust/tasks/mod.rs +28 -4
- package/src/rust/tasks/pipeline.rs +411 -0
- package/src/rust/tasks/presize_panels.rs +324 -0
- package/src/rust/tasks/reset_all.rs +22 -12
- package/src/rust/tasks/resize_observer.rs +124 -87
- package/src/rust/tasks/restore_and_render.rs +80 -86
- package/src/rust/tasks/restore_panel.rs +145 -0
- package/src/rust/tasks/send_column_config.rs +5 -2
- package/src/rust/tasks/send_plugin_config.rs +5 -2
- package/src/rust/tasks/set_edit_mode.rs +59 -0
- package/src/rust/tasks/sync_update_panels.rs +152 -0
- package/src/rust/tasks/table_lifecycle.rs +158 -0
- package/src/rust/tasks/update_theme.rs +56 -12
- package/src/rust/utils/completion.rs +56 -0
- package/src/rust/utils/custom_element.rs +5 -0
- package/src/rust/utils/debounce.rs +130 -7
- package/src/rust/utils/mod.rs +6 -0
- package/src/rust/utils/pending_effects.rs +62 -0
- package/src/rust/{components/style/local_style.rs → utils/spawn.rs} +17 -19
- package/src/rust/utils/weak_scope.rs +0 -10
- package/src/rust/workspace.rs +846 -0
- package/src/svg/active-indicator.svg +3 -0
- package/src/themes/botanical.css +7 -2
- package/src/themes/defaults.css +54 -2
- package/src/themes/dracula.css +8 -3
- package/src/themes/gruvbox-dark.css +7 -2
- package/src/themes/gruvbox.css +5 -2
- package/src/themes/icons.css +4 -2
- package/src/themes/monokai.css +7 -2
- package/src/themes/phosphor.css +7 -2
- package/src/themes/pro-dark.css +7 -2
- package/src/themes/pro.css +2 -1
- package/src/themes/solarized-dark.css +5 -2
- package/src/themes/solarized.css +5 -2
- package/src/themes/vaporwave.css +7 -2
- package/src/ts/bootstrap.ts +8 -7
- package/src/ts/extensions.ts +30 -2
- package/src/ts/perspective-viewer.ts +10 -0
- package/src/ts/plugin.ts +72 -5
- package/src/ts/ts-rs/ClientOptions.ts +7 -0
- package/src/ts/ts-rs/ExportMethod.ts +3 -0
- package/src/ts/ts-rs/ExportOptions.ts +8 -0
- package/src/ts/ts-rs/GetClientOptions.ts +7 -0
- package/src/ts/ts-rs/GetTableOptions.ts +7 -0
- package/src/ts/ts-rs/Layout.ts +9 -0
- package/src/ts/ts-rs/Orientation.ts +6 -0
- package/src/ts/ts-rs/PanelOptions.ts +7 -0
- package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
- package/src/ts/ts-rs/SplitLayout.ts +5 -0
- package/src/ts/ts-rs/TabLayout.ts +11 -0
- package/src/ts/ts-rs/ViewerConfig.ts +6 -2
- package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
- package/tsconfig.json +1 -1
- package/src/rust/components/style/style_cache.rs +0 -136
- package/src/rust/tasks/intersection_observer.rs +0 -98
- package/src/rust/tasks/update_and_render.rs +0 -110
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline4.js → perspective-viewer-daeef4ceb066e6c7/inline5.js} +0 -0
|
@@ -19,9 +19,6 @@ use web_sys::HtmlElement;
|
|
|
19
19
|
use yew::html::Scope;
|
|
20
20
|
use yew::prelude::*;
|
|
21
21
|
|
|
22
|
-
use crate::components::style::LocalStyle;
|
|
23
|
-
use crate::css;
|
|
24
|
-
|
|
25
22
|
#[derive(Properties, Default)]
|
|
26
23
|
pub struct SplitPanelProps {
|
|
27
24
|
pub children: Children,
|
|
@@ -32,8 +29,10 @@ pub struct SplitPanelProps {
|
|
|
32
29
|
#[prop_or_default]
|
|
33
30
|
pub orientation: Orientation,
|
|
34
31
|
|
|
35
|
-
/// Whether to
|
|
36
|
-
///
|
|
32
|
+
/// Whether to OMIT children that render nothing (an empty fragment, or
|
|
33
|
+
/// any nesting of empty fragments — see [`is_empty_html`]) instead of
|
|
34
|
+
/// rendering them as empty panes. A skipped pane takes its divider with
|
|
35
|
+
/// it.
|
|
37
36
|
#[prop_or_default]
|
|
38
37
|
pub skip_empty: bool,
|
|
39
38
|
|
|
@@ -56,6 +55,50 @@ pub struct SplitPanelProps {
|
|
|
56
55
|
|
|
57
56
|
#[prop_or_default]
|
|
58
57
|
pub initial_size: Option<i32>,
|
|
58
|
+
|
|
59
|
+
/// When `true`, a divider drag does NOT apply pane sizes directly:
|
|
60
|
+
/// `MoveResizing` only emits `on_resize` with the proposed dims, and pane
|
|
61
|
+
/// 0's committed size is driven exclusively by the controlled
|
|
62
|
+
/// [`Self::size`] prop — set by the parent when it is ready (e.g. after
|
|
63
|
+
/// pre-rendering panel content at the target size). This is the presize
|
|
64
|
+
/// gate for continuous divider drags (`PRESIZE_EVERYWHERE_PLAN.md`,
|
|
65
|
+
/// P1): geometry never outruns content. Only meaningful when the
|
|
66
|
+
/// resizable pane is child 0 (as in the viewer's `app_panel`).
|
|
67
|
+
#[prop_or_default]
|
|
68
|
+
pub deferred: bool,
|
|
69
|
+
|
|
70
|
+
/// Controlled committed size for pane 0 (deferred mode). Unlike
|
|
71
|
+
/// [`Self::initial_size`] (read once at `create`), changes to this prop
|
|
72
|
+
/// re-derive pane 0's style on every `changed`.
|
|
73
|
+
#[prop_or_default]
|
|
74
|
+
pub size: Option<i32>,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// `true` when `node` renders NOTHING: an empty fragment, or a fragment of
|
|
78
|
+
/// nothing but empty fragments. SEMANTIC, not literal — the `html!`
|
|
79
|
+
/// if-syntax (and other wrappers) nests an empty branch inside another
|
|
80
|
+
/// `VList` rather than yielding a bare `<></>`, which is why a literal
|
|
81
|
+
/// `x != html! { <></> }` comparison is not a usable emptiness test (see
|
|
82
|
+
/// the mechanism unit test). Deliberately conservative: `VText("")` and
|
|
83
|
+
/// other node kinds are NOT considered empty.
|
|
84
|
+
fn is_empty_html(node: &Html) -> bool {
|
|
85
|
+
match node {
|
|
86
|
+
Html::VList(list) => list.iter().all(is_empty_html),
|
|
87
|
+
_ => false,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// The fixed-size pane style for a committed size (the complement pane
|
|
92
|
+
/// flex-fills).
|
|
93
|
+
fn size_style(orientation: Orientation, x: i32) -> String {
|
|
94
|
+
match orientation {
|
|
95
|
+
Orientation::Horizontal => {
|
|
96
|
+
format!("max-width:{x}px;min-width:{x}px;width:{x}px")
|
|
97
|
+
},
|
|
98
|
+
Orientation::Vertical => {
|
|
99
|
+
format!("max-height:{x}px;min-height:{x}px;height:{x}px")
|
|
100
|
+
},
|
|
101
|
+
}
|
|
59
102
|
}
|
|
60
103
|
|
|
61
104
|
impl SplitPanelProps {
|
|
@@ -70,6 +113,8 @@ impl PartialEq for SplitPanelProps {
|
|
|
70
113
|
&& self.children == other.children
|
|
71
114
|
&& self.orientation == other.orientation
|
|
72
115
|
&& self.reverse == other.reverse
|
|
116
|
+
&& self.size == other.size
|
|
117
|
+
&& self.deferred == other.deferred
|
|
73
118
|
}
|
|
74
119
|
}
|
|
75
120
|
|
|
@@ -114,15 +159,8 @@ impl Component for SplitPanel {
|
|
|
114
159
|
let refs = Vec::from_iter(std::iter::repeat_with(Default::default).take(len));
|
|
115
160
|
|
|
116
161
|
let mut styles = vec![Default::default(); len];
|
|
117
|
-
if let Some(x) =
|
|
118
|
-
styles[0] = Some(
|
|
119
|
-
Orientation::Horizontal => {
|
|
120
|
-
format!("max-width:{x}px;min-width:{x}px;width:{x}px")
|
|
121
|
-
},
|
|
122
|
-
Orientation::Vertical => {
|
|
123
|
-
format!("max-height:{x}px;min-height:{x}px;height:{x}px")
|
|
124
|
-
},
|
|
125
|
-
});
|
|
162
|
+
if let Some(x) = ctx.props().size.or(ctx.props().initial_size) {
|
|
163
|
+
styles[0] = Some(size_style(ctx.props().orientation, x));
|
|
126
164
|
}
|
|
127
165
|
|
|
128
166
|
Self {
|
|
@@ -158,7 +196,12 @@ impl Component for SplitPanel {
|
|
|
158
196
|
cb.emit(state.get_dimensions(client_offset));
|
|
159
197
|
}
|
|
160
198
|
|
|
161
|
-
|
|
199
|
+
// Deferred mode: propose only — the committed size arrives
|
|
200
|
+
// back through the controlled `size` prop once the parent
|
|
201
|
+
// has pre-rendered content at the target.
|
|
202
|
+
if !ctx.props().deferred {
|
|
203
|
+
self.styles[state.index] = state.get_style(client_offset);
|
|
204
|
+
}
|
|
162
205
|
}
|
|
163
206
|
},
|
|
164
207
|
};
|
|
@@ -176,19 +219,91 @@ impl Component for SplitPanel {
|
|
|
176
219
|
let new_len = ctx.props().children.len();
|
|
177
220
|
self.refs.resize_with(new_len, Default::default);
|
|
178
221
|
self.styles.resize(new_len, Default::default());
|
|
222
|
+
|
|
223
|
+
if let Some(state) = self.resize_state.as_ref() {
|
|
224
|
+
let skip_empty = ctx.props().skip_empty;
|
|
225
|
+
let still_visible = ctx
|
|
226
|
+
.props()
|
|
227
|
+
.children
|
|
228
|
+
.iter()
|
|
229
|
+
.enumerate()
|
|
230
|
+
.any(|(i, x)| i == state.index && (!skip_empty || !is_empty_html(&x)));
|
|
231
|
+
|
|
232
|
+
if !still_visible {
|
|
233
|
+
self.resize_state = None;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Deferred mode: pane 0's style tracks the controlled `size` prop
|
|
238
|
+
// (`None` = natural width, e.g. after a divider double-click reset).
|
|
239
|
+
if ctx.props().deferred {
|
|
240
|
+
self.styles[0] = ctx
|
|
241
|
+
.props()
|
|
242
|
+
.size
|
|
243
|
+
.map(|x| size_style(ctx.props().orientation, x));
|
|
244
|
+
}
|
|
245
|
+
|
|
179
246
|
true
|
|
180
247
|
}
|
|
181
248
|
|
|
182
249
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
183
|
-
let
|
|
250
|
+
let skip_empty = ctx.props().skip_empty;
|
|
251
|
+
let orientation = ctx.props().orientation;
|
|
252
|
+
|
|
253
|
+
// Pair each *visible* pane with its ORIGINAL child index and key every
|
|
254
|
+
// pane (and divider) by that stable identity — not its post-filter
|
|
255
|
+
// position. Toggling one pane in/out (e.g. the settings sidebar) then
|
|
256
|
+
// never shifts a sibling's key, so Yew reconciles the survivor in place
|
|
257
|
+
// rather than remounting it. A `MainPanel` remount here would tear down
|
|
258
|
+
// and recreate the embedded `<regular-layout>` and the `<slot>`s
|
|
259
|
+
// projecting the plugins — the bug this avoids. Dividers are independent
|
|
260
|
+
// keyed nodes for the same reason: a divider appearing before a pane must
|
|
261
|
+
// not alter that pane's own keyed subtree.
|
|
262
|
+
let panes = ctx
|
|
184
263
|
.props()
|
|
185
264
|
.children
|
|
186
265
|
.iter()
|
|
187
|
-
.filter(|x| !ctx.props().skip_empty || x != &html! { <></> })
|
|
188
266
|
.enumerate()
|
|
267
|
+
.filter(|(_, x)| !skip_empty || !is_empty_html(x))
|
|
189
268
|
.collect::<Vec<_>>();
|
|
190
269
|
|
|
191
|
-
let
|
|
270
|
+
let last = panes.len().saturating_sub(1);
|
|
271
|
+
let mut nodes: Vec<Html> = Vec::with_capacity(panes.len() * 2);
|
|
272
|
+
let mut prev: Option<usize> = None;
|
|
273
|
+
for (pos, (i, x)) in panes.into_iter().enumerate() {
|
|
274
|
+
// A divider precedes every visible pane except the first; it resizes
|
|
275
|
+
// the *previous* visible pane (`prev`, an original index).
|
|
276
|
+
if let Some(p) = prev {
|
|
277
|
+
nodes.push(html! {
|
|
278
|
+
<SplitPanelDivider
|
|
279
|
+
key={format!("divider-{i}")}
|
|
280
|
+
i={p}
|
|
281
|
+
{orientation}
|
|
282
|
+
link={ctx.link().clone()}
|
|
283
|
+
/>
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// The last visible pane flex-fills (rendered bare, no width
|
|
288
|
+
// override); earlier panes are `SplitPanelChild`s that can carry a
|
|
289
|
+
// dragged size.
|
|
290
|
+
nodes.push(if pos == last {
|
|
291
|
+
html! { <key={i}>{ x }</> }
|
|
292
|
+
} else {
|
|
293
|
+
html! {
|
|
294
|
+
<SplitPanelChild
|
|
295
|
+
key={i}
|
|
296
|
+
style={self.styles[i].clone()}
|
|
297
|
+
ref_={self.refs[i].clone()}
|
|
298
|
+
>
|
|
299
|
+
{ x }
|
|
300
|
+
</SplitPanelChild>
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
prev = Some(i);
|
|
305
|
+
}
|
|
306
|
+
|
|
192
307
|
let mut classes = classes!("split-panel");
|
|
193
308
|
if orientation == Orientation::Vertical {
|
|
194
309
|
classes.push("orient-vertical");
|
|
@@ -198,54 +313,7 @@ impl Component for SplitPanel {
|
|
|
198
313
|
classes.push("orient-reverse");
|
|
199
314
|
}
|
|
200
315
|
|
|
201
|
-
let
|
|
202
|
-
let contents = html! {
|
|
203
|
-
<>
|
|
204
|
-
<LocalStyle href={css!("containers/split-panel")} />
|
|
205
|
-
for (i, x) in iter {
|
|
206
|
-
if i == 0 {
|
|
207
|
-
if count == 1 {
|
|
208
|
-
<key=0>
|
|
209
|
-
{x}
|
|
210
|
-
</>
|
|
211
|
-
} else {
|
|
212
|
-
<SplitPanelChild
|
|
213
|
-
key=0
|
|
214
|
-
style={self.styles[i].clone()}
|
|
215
|
-
ref_={self.refs[i].clone()}
|
|
216
|
-
>
|
|
217
|
-
{ x }
|
|
218
|
-
</SplitPanelChild>
|
|
219
|
-
}
|
|
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
|
-
}
|
|
244
|
-
}
|
|
245
|
-
</>
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
// TODO consider removing this
|
|
316
|
+
let contents = html! { <>{ for nodes.into_iter() }</> };
|
|
249
317
|
if ctx.props().no_wrap {
|
|
250
318
|
html! { { contents } }
|
|
251
319
|
} else {
|
|
@@ -494,3 +562,44 @@ impl ResizingState {
|
|
|
494
562
|
Ok(self.body_style.set_property("cursor", &self.cursor)?)
|
|
495
563
|
}
|
|
496
564
|
}
|
|
565
|
+
|
|
566
|
+
#[cfg(test)]
|
|
567
|
+
mod tests {
|
|
568
|
+
use super::*;
|
|
569
|
+
|
|
570
|
+
#[test]
|
|
571
|
+
fn html_if_empty_branch_is_not_literally_empty() {
|
|
572
|
+
let via_if: Html = html! { if false { <div /> } else { <></> } };
|
|
573
|
+
assert_ne!(via_if, html! { <></> });
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
#[test]
|
|
577
|
+
fn empty_fragment_is_empty() {
|
|
578
|
+
assert!(is_empty_html(&html! { <></> }));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
#[test]
|
|
582
|
+
fn html_if_empty_branch_is_semantically_empty() {
|
|
583
|
+
assert!(is_empty_html(&html! { if false { <div/> } else { <></> } }));
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
#[test]
|
|
587
|
+
fn nested_empty_fragments_are_empty() {
|
|
588
|
+
assert!(is_empty_html(&html! { <><><></></></> }));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
#[test]
|
|
592
|
+
fn tag_is_not_empty() {
|
|
593
|
+
assert!(!is_empty_html(&html! { <div/> }));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
#[test]
|
|
597
|
+
fn fragment_containing_a_tag_is_not_empty() {
|
|
598
|
+
assert!(!is_empty_html(&html! { <><div/></> }));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
#[test]
|
|
602
|
+
fn text_is_not_empty() {
|
|
603
|
+
assert!(!is_empty_html(&html! { { "" } }));
|
|
604
|
+
}
|
|
605
|
+
}
|
|
@@ -12,8 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
use yew::{Callback, Children, Component, Html, Properties, classes, html};
|
|
14
14
|
|
|
15
|
-
use crate::components::style::LocalStyle;
|
|
16
|
-
use crate::css;
|
|
17
15
|
use crate::presentation::ColumnTab;
|
|
18
16
|
|
|
19
17
|
#[derive(Properties, Debug, PartialEq)]
|
|
@@ -87,7 +85,6 @@ impl<T: ColumnTab> Component for TabList<T> {
|
|
|
87
85
|
|
|
88
86
|
html! {
|
|
89
87
|
<>
|
|
90
|
-
<LocalStyle href={css!("containers/tabs")} />
|
|
91
88
|
<div id="settings_tab_bar">{ for gutter_tabs }</div>
|
|
92
89
|
<div id="format-tab" class="tab-content scrollable">
|
|
93
90
|
{ ctx.props().children.iter().nth(self.selected_idx) }
|
|
@@ -0,0 +1,130 @@
|
|
|
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 web_sys::MouseEvent;
|
|
14
|
+
use yew::prelude::*;
|
|
15
|
+
|
|
16
|
+
/// A single command row in a [`ContextMenu`].
|
|
17
|
+
#[derive(Clone, PartialEq)]
|
|
18
|
+
pub struct ContextMenuItem {
|
|
19
|
+
pub label: String,
|
|
20
|
+
pub on_select: Callback<()>,
|
|
21
|
+
pub disabled: bool,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// A row in a [`ContextMenu`]: a plain command [`ContextMenuItem`], a
|
|
25
|
+
/// non-interactive group label, or a row with a hover-opened sub-menu flyout.
|
|
26
|
+
#[derive(Clone, PartialEq)]
|
|
27
|
+
pub enum ContextMenuEntry {
|
|
28
|
+
Item(ContextMenuItem),
|
|
29
|
+
Header(String),
|
|
30
|
+
Submenu {
|
|
31
|
+
label: String,
|
|
32
|
+
|
|
33
|
+
/// Click-through command for the parent row itself (`None` makes the
|
|
34
|
+
/// row hover-only).
|
|
35
|
+
on_select: Option<Callback<()>>,
|
|
36
|
+
entries: Vec<ContextMenuEntry>,
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#[derive(Properties, PartialEq)]
|
|
41
|
+
pub struct ContextMenuProps {
|
|
42
|
+
pub entries: Vec<ContextMenuEntry>,
|
|
43
|
+
|
|
44
|
+
/// Fired after an item is selected. Outside-click dismissal is the
|
|
45
|
+
/// enclosing `PortalModal`'s job (blur), not this component's.
|
|
46
|
+
#[prop_or_default]
|
|
47
|
+
pub on_close: Callback<()>,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// The command-item list of a panel context menu. Purely presentational — the
|
|
51
|
+
/// command set is supplied by the parent as plain [`Callback`]s, and
|
|
52
|
+
/// positioning/dismissal/theming belong to the enclosing `PortalModal` (the
|
|
53
|
+
/// same body-mounted, `theme`-attributed delivery as the Export/Copy menus).
|
|
54
|
+
/// Sub-menus are CSS-only `:hover` flyouts nested inside their parent row, so
|
|
55
|
+
/// they live inside the same `PortalModal` host (focus never leaves it) and
|
|
56
|
+
/// selection routes through the same `on_select` + `on_close` path.
|
|
57
|
+
pub struct ContextMenu;
|
|
58
|
+
|
|
59
|
+
impl Component for ContextMenu {
|
|
60
|
+
type Message = ();
|
|
61
|
+
type Properties = ContextMenuProps;
|
|
62
|
+
|
|
63
|
+
fn create(_ctx: &Context<Self>) -> Self {
|
|
64
|
+
Self
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
68
|
+
let props = ctx.props();
|
|
69
|
+
let entries = props
|
|
70
|
+
.entries
|
|
71
|
+
.iter()
|
|
72
|
+
.map(|entry| render_entry(entry, &props.on_close));
|
|
73
|
+
|
|
74
|
+
html! { <div class="context-menu">{ for entries }</div> }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn render_entry(entry: &ContextMenuEntry, on_close: &Callback<()>) -> Html {
|
|
79
|
+
match entry {
|
|
80
|
+
ContextMenuEntry::Item(item) => {
|
|
81
|
+
let disabled = item.disabled;
|
|
82
|
+
let onclick = {
|
|
83
|
+
let on_select = item.on_select.clone();
|
|
84
|
+
let on_close = on_close.clone();
|
|
85
|
+
Callback::from(move |e: MouseEvent| {
|
|
86
|
+
e.stop_propagation();
|
|
87
|
+
if !disabled {
|
|
88
|
+
on_select.emit(());
|
|
89
|
+
on_close.emit(());
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
let mut class = classes!("context-menu-item");
|
|
95
|
+
if disabled {
|
|
96
|
+
class.push("disabled");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
html! { <span {class} {onclick}>{ item.label.clone() }</span> }
|
|
100
|
+
},
|
|
101
|
+
ContextMenuEntry::Header(label) => {
|
|
102
|
+
html! { <span class="context-menu-header">{ label.clone() }</span> }
|
|
103
|
+
},
|
|
104
|
+
ContextMenuEntry::Submenu {
|
|
105
|
+
label,
|
|
106
|
+
on_select,
|
|
107
|
+
entries,
|
|
108
|
+
} => {
|
|
109
|
+
let onclick = {
|
|
110
|
+
let on_select = on_select.clone();
|
|
111
|
+
let on_close = on_close.clone();
|
|
112
|
+
Callback::from(move |e: MouseEvent| {
|
|
113
|
+
e.stop_propagation();
|
|
114
|
+
if let Some(on_select) = &on_select {
|
|
115
|
+
on_select.emit(());
|
|
116
|
+
on_close.emit(());
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
let children = entries.iter().map(|entry| render_entry(entry, on_close));
|
|
122
|
+
html! {
|
|
123
|
+
<span class="context-menu-item has-submenu" {onclick}>
|
|
124
|
+
{ label.clone() }
|
|
125
|
+
<div class="context-menu context-menu-submenu">{ for children }</div>
|
|
126
|
+
</span>
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -23,12 +23,10 @@ use wasm_bindgen::prelude::*;
|
|
|
23
23
|
use yew::prelude::*;
|
|
24
24
|
|
|
25
25
|
use super::modal::{ModalLink, SetModalLink};
|
|
26
|
-
use super::style::LocalStyle;
|
|
27
26
|
use crate::components::datetime_column_style::custom::DatetimeStyleCustom;
|
|
28
27
|
use crate::components::datetime_column_style::simple::DatetimeStyleSimple;
|
|
29
28
|
use crate::components::form::select_value_field::SelectValueField;
|
|
30
29
|
use crate::config::*;
|
|
31
|
-
use crate::css;
|
|
32
30
|
use crate::utils::WeakScope;
|
|
33
31
|
|
|
34
32
|
/// Format-only widget for `datetime` columns. Renders the `date_format`
|
|
@@ -126,7 +124,6 @@ impl Component for DatetimeColumnStyle {
|
|
|
126
124
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
127
125
|
html! {
|
|
128
126
|
<>
|
|
129
|
-
<LocalStyle href={css!("column-style")} />
|
|
130
127
|
<div id="column-style-container" class="datetime-column-style-container">
|
|
131
128
|
if ctx.props().enable_time_config {
|
|
132
129
|
<SelectValueField<String>
|
|
@@ -20,8 +20,6 @@ use web_sys::*;
|
|
|
20
20
|
use yew::prelude::*;
|
|
21
21
|
|
|
22
22
|
use crate::components::filter_dropdown::FilterDropDownElement;
|
|
23
|
-
use crate::components::style::LocalStyle;
|
|
24
|
-
use crate::css;
|
|
25
23
|
|
|
26
24
|
#[derive(Properties, Derivative)]
|
|
27
25
|
#[derivative(Debug)]
|
|
@@ -87,7 +85,6 @@ impl Component for EmptyRow {
|
|
|
87
85
|
|
|
88
86
|
html! {
|
|
89
87
|
<div class="pivot-column column-empty">
|
|
90
|
-
<LocalStyle href={css!("empty-column")} />
|
|
91
88
|
<input
|
|
92
89
|
spellcheck="false"
|
|
93
90
|
ref={self.input_ref.clone()}
|
|
@@ -16,10 +16,8 @@ use perspective_client::{ExprValidationError, clone};
|
|
|
16
16
|
use yew::prelude::*;
|
|
17
17
|
|
|
18
18
|
use super::form::code_editor::*;
|
|
19
|
-
use super::style::LocalStyle;
|
|
20
19
|
use crate::session::{Session, SessionMetadata, SessionMetadataRc};
|
|
21
20
|
use crate::tasks::{ExprValidation, validate_expression};
|
|
22
|
-
use crate::*;
|
|
23
21
|
|
|
24
22
|
#[derive(Properties, PartialEq, Clone)]
|
|
25
23
|
pub struct ExpressionEditorProps {
|
|
@@ -54,10 +52,12 @@ pub struct ExpressionEditor {
|
|
|
54
52
|
expr: Rc<String>,
|
|
55
53
|
error: Option<ExprValidationError>,
|
|
56
54
|
oninput: Callback<Rc<String>>,
|
|
55
|
+
|
|
57
56
|
/// Monotonically increasing request id used to drop stale
|
|
58
57
|
/// validation results when the user types faster than the engine
|
|
59
58
|
/// can validate.
|
|
60
59
|
validation_req_id: u64,
|
|
60
|
+
|
|
61
61
|
/// The id of the most recently dispatched validation; the result
|
|
62
62
|
/// is only applied when its echoed id matches.
|
|
63
63
|
last_dispatched_req_id: u64,
|
|
@@ -131,7 +131,6 @@ impl Component for ExpressionEditor {
|
|
|
131
131
|
clone!(ctx.props().disabled);
|
|
132
132
|
html! {
|
|
133
133
|
<>
|
|
134
|
-
<LocalStyle href={css!("expression-editor")} />
|
|
135
134
|
<label class="item_title">{ "Expression" }</label>
|
|
136
135
|
<div id="editor-container" class={disabled_class}>
|
|
137
136
|
<CodeEditor
|
|
@@ -20,12 +20,11 @@ use yew::html::ImplicitClone;
|
|
|
20
20
|
use yew::prelude::*;
|
|
21
21
|
|
|
22
22
|
use super::portal::PortalModal;
|
|
23
|
+
use super::style::StyleSurface;
|
|
23
24
|
use crate::session::Session;
|
|
24
25
|
use crate::utils::*;
|
|
25
26
|
use crate::*;
|
|
26
27
|
|
|
27
|
-
static CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/css/filter-dropdown.css"));
|
|
28
|
-
|
|
29
28
|
#[derive(Default)]
|
|
30
29
|
struct FilterDropDownState {
|
|
31
30
|
values: Vec<String>,
|
|
@@ -220,6 +219,7 @@ impl Component for FilterDropDownPortal {
|
|
|
220
219
|
html! {
|
|
221
220
|
<PortalModal
|
|
222
221
|
tag_name="perspective-dropdown"
|
|
222
|
+
surface={StyleSurface::FilterDropdown}
|
|
223
223
|
{target}
|
|
224
224
|
own_focus=false
|
|
225
225
|
{on_close}
|
|
@@ -267,7 +267,7 @@ fn FilterDropDownView(props: &FilterDropDownViewProps) -> Html {
|
|
|
267
267
|
}
|
|
268
268
|
};
|
|
269
269
|
|
|
270
|
-
html! {
|
|
270
|
+
html! { <>{ body }</> }
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
fn filter_values(
|
|
@@ -154,12 +154,12 @@ impl FontLoaderProps {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
let fut = async { select_all(block_fonts
|
|
157
|
+
let fut = async { select_all(block_fonts).await.0 };
|
|
158
158
|
block_promises.push(ApiFuture::new(fut))
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
if block_promises.len() != preload_fonts.len() {
|
|
162
|
-
web_sys::console::warn_1(&format!("Missing preload fonts {:?}",
|
|
162
|
+
web_sys::console::warn_1(&format!("Missing preload fonts {:?}", preload_fonts).into());
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
let res = join_all(block_promises)
|
|
@@ -19,8 +19,6 @@ use yew::prelude::*;
|
|
|
19
19
|
|
|
20
20
|
use crate::components::form::highlight::highlight;
|
|
21
21
|
use crate::components::function_dropdown::{FunctionDropDownElement, FunctionDropDownPortal};
|
|
22
|
-
use crate::components::style::LocalStyle;
|
|
23
|
-
use crate::css;
|
|
24
22
|
use crate::exprtk::{Cursor, tokenize};
|
|
25
23
|
use crate::utils::*;
|
|
26
24
|
|
|
@@ -174,7 +172,6 @@ pub fn code_editor(props: &CodeEditorProps) -> Html {
|
|
|
174
172
|
clone!(props.disabled);
|
|
175
173
|
html! {
|
|
176
174
|
<>
|
|
177
|
-
<LocalStyle href={css!("form/code-editor")} />
|
|
178
175
|
<div id="editor" {class}>
|
|
179
176
|
<div id="line_numbers" ref={lineno_ref}>{ line_numbers }</div>
|
|
180
177
|
<div id="editor-inner" {class}>
|
|
@@ -18,8 +18,6 @@ use wasm_bindgen::prelude::*;
|
|
|
18
18
|
use yew::prelude::*;
|
|
19
19
|
|
|
20
20
|
use crate::components::form::code_editor::CodeEditor;
|
|
21
|
-
use crate::components::style::LocalStyle;
|
|
22
|
-
use crate::css;
|
|
23
21
|
use crate::js::{MimeType, copy_to_clipboard, paste_from_clipboard};
|
|
24
22
|
use crate::presentation::*;
|
|
25
23
|
use crate::renderer::*;
|
|
@@ -166,8 +164,6 @@ pub fn debug_panel(props: &DebugPanelProps) -> Html {
|
|
|
166
164
|
|
|
167
165
|
html! {
|
|
168
166
|
<>
|
|
169
|
-
<LocalStyle href={css!("containers/tabs")} />
|
|
170
|
-
<LocalStyle href={css!("form/debug")} />
|
|
171
167
|
<div id="debug-panel-overflow">
|
|
172
168
|
<div id="debug-panel" class="sidebar_column" ref={sizer}>
|
|
173
169
|
<div id="debug-panel-controls">
|
|
@@ -244,6 +240,9 @@ impl DebugPanelProps {
|
|
|
244
240
|
&props.session,
|
|
245
241
|
&props.renderer,
|
|
246
242
|
&props.presentation,
|
|
243
|
+
// A user-pasted config apply — an explicit request,
|
|
244
|
+
// same affordance as the public `restore()`.
|
|
245
|
+
crate::tasks::RunOrigin::Public,
|
|
247
246
|
config,
|
|
248
247
|
async { Ok(()) },
|
|
249
248
|
)
|
|
@@ -20,10 +20,9 @@ use yew::html::ImplicitClone;
|
|
|
20
20
|
use yew::prelude::*;
|
|
21
21
|
|
|
22
22
|
use super::portal::PortalModal;
|
|
23
|
+
use super::style::StyleSurface;
|
|
23
24
|
use crate::utils::*;
|
|
24
25
|
|
|
25
|
-
static CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/css/function-dropdown.css"));
|
|
26
|
-
|
|
27
26
|
#[derive(Default)]
|
|
28
27
|
struct FunctionDropDownState {
|
|
29
28
|
values: Vec<CompletionItemSuggestion>,
|
|
@@ -158,6 +157,7 @@ impl Component for FunctionDropDownPortal {
|
|
|
158
157
|
html! {
|
|
159
158
|
<PortalModal
|
|
160
159
|
tag_name="perspective-dropdown"
|
|
160
|
+
surface={StyleSurface::FunctionDropdown}
|
|
161
161
|
{target}
|
|
162
162
|
own_focus=false
|
|
163
163
|
{on_close}
|
|
@@ -211,7 +211,7 @@ fn FunctionDropDownView(props: &FunctionDropDownViewProps) -> Html {
|
|
|
211
211
|
}
|
|
212
212
|
};
|
|
213
213
|
|
|
214
|
-
html! {
|
|
214
|
+
html! { <>{ body }</> }
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
fn filter_values(input: &str) -> Vec<CompletionItemSuggestion> {
|