@perspective-dev/viewer 5.3.0 → 5.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.
- package/dist/cdn/perspective-viewer.js +8 -8
- package/dist/cdn/perspective-viewer.js.map +3 -3
- package/dist/css/blueprint.css +1 -0
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/eggplant.css +1 -0
- 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/intl/ar.css +1 -0
- package/dist/css/intl/de.css +1 -1
- package/dist/css/intl/es.css +1 -1
- package/dist/css/intl/fr.css +1 -1
- package/dist/css/intl/ja.css +1 -1
- package/dist/css/intl/pt.css +1 -1
- package/dist/css/intl/zh.css +1 -1
- package/dist/css/intl.css +1 -1
- package/dist/css/ledger.css +1 -0
- package/dist/css/monokai.css +1 -1
- package/dist/css/nord.css +1 -0
- 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/css/velvet.css +1 -0
- package/dist/docs/perspective-docs.json +1 -1
- package/dist/esm/column-format.d.ts +16 -3
- package/dist/esm/extensions.d.ts +0 -5
- package/dist/esm/perspective-viewer.inline.js +7 -7
- package/dist/esm/perspective-viewer.inline.js.map +3 -3
- package/dist/esm/perspective-viewer.js +8 -8
- package/dist/esm/perspective-viewer.js.map +3 -3
- package/dist/esm/ts-rs/ViewOnUpdateResp.d.ts +1 -1
- package/dist/wasm/perspective-viewer.d.ts +62 -73
- package/dist/wasm/perspective-viewer.js +230 -238
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +18 -28
- package/package.json +7 -7
- package/src/css/_context_menu.css +1 -1
- package/src/css/_dropdown_menu.css +1 -1
- package/src/css/_viewer_bundle.css +7 -8
- package/src/css/column-dropdown.css +0 -3
- package/src/css/column-selector.css +8 -5
- package/src/css/column-settings-panel.css +0 -206
- package/src/css/column-style.css +95 -0
- package/src/css/config-selector.css +18 -10
- package/src/css/filter-dropdown.css +5 -5
- package/src/css/form/debug.css +28 -4
- package/src/css/function-dropdown.css +5 -5
- package/src/css/panel-tab.css +23 -0
- package/src/css/plugin-selector.css +6 -5
- package/src/css/render-warning.css +1 -1
- package/src/css/status-bar.css +52 -21
- package/src/css/type-icon.css +1 -3
- package/src/css/{containers → ui/containers}/context-menu.css +22 -16
- package/src/css/ui/containers/dropdown-menu-items.css +66 -0
- package/src/css/{containers → ui/containers}/dropdown-menu.css +8 -53
- package/src/css/{containers → ui/containers}/tabs.css +13 -3
- package/src/css/{dom → ui/dom}/select.css +19 -8
- package/src/css/viewer.css +32 -31
- package/src/rust/agent/tools.rs +5 -2
- package/src/rust/components/chat_panel.rs +1 -1
- package/src/rust/components/{form/code_editor.rs → code_editor.rs} +4 -2
- package/src/rust/components/column_dropdown.rs +2 -2
- package/src/rust/components/column_selector/active_column.rs +15 -9
- package/src/rust/components/column_selector/aggregate_selector.rs +1 -1
- package/src/rust/components/column_selector/config_selector.rs +2 -2
- package/src/rust/components/column_selector/filter_column.rs +8 -5
- package/src/rust/components/column_selector/inactive_column.rs +4 -2
- package/src/rust/components/column_selector/pivot_column.rs +4 -3
- package/src/rust/components/column_selector/sort_column.rs +7 -4
- package/src/rust/components/column_selector.rs +3 -3
- package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +15 -17
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab.rs +296 -238
- package/src/rust/components/column_settings_sidebar.rs +3 -4
- package/src/rust/components/copy_dropdown.rs +1 -1
- package/src/rust/components/datetime_column_style/custom.rs +1 -3
- package/src/rust/components/datetime_column_style/simple.rs +16 -6
- package/src/rust/components/datetime_column_style.rs +51 -12
- package/src/rust/components/{form/debug.rs → debug_panel.rs} +5 -5
- package/src/rust/components/{containers/dragdrop_list.rs → dragdrop_list.rs} +2 -10
- package/src/rust/components/export_dropdown.rs +1 -1
- package/src/rust/components/expression_editor.rs +1 -1
- package/src/rust/components/filter_dropdown.rs +2 -2
- package/src/rust/components/function_dropdown.rs +2 -2
- package/src/rust/components/main_panel/frame_theme.rs +3 -59
- package/src/rust/components/main_panel/reconcile.rs +9 -4
- package/src/rust/components/main_panel/render.rs +62 -11
- package/src/rust/components/main_panel/update.rs +39 -10
- package/src/rust/components/main_panel.rs +26 -2
- package/src/rust/components/mod.rs +5 -7
- package/src/rust/components/new_panel_menu.rs +97 -0
- package/src/rust/components/number_series_style.rs +2 -3
- package/src/rust/components/panel_menu.rs +61 -87
- package/src/rust/components/panel_tab.rs +100 -43
- package/src/rust/components/plugin_tab.rs +125 -87
- package/src/rust/components/render_warning.rs +2 -2
- package/src/rust/components/{status_bar_counter.rs → rows_counter.rs} +10 -10
- package/src/rust/components/settings_panel.rs +3 -2
- package/src/rust/components/status_bar.rs +113 -20
- package/src/rust/components/status_indicator.rs +5 -14
- package/src/rust/components/string_column_style.rs +1 -2
- package/src/rust/components/{style/mod.rs → style.rs} +32 -15
- package/src/rust/components/style_controls/number_string_format/digits_section.rs +25 -15
- package/src/rust/components/style_controls/number_string_format/misc_section.rs +7 -3
- package/src/rust/components/style_controls/number_string_format/style_section.rs +2 -1
- package/src/rust/components/style_controls/number_string_format/types.rs +24 -0
- package/src/rust/components/style_controls/number_string_format.rs +37 -14
- package/src/rust/components/viewer/msg.rs +43 -30
- package/src/rust/components/viewer/panels.rs +50 -19
- package/src/rust/components/viewer/render.rs +15 -13
- package/src/rust/components/viewer/settings.rs +137 -68
- package/src/rust/components/viewer/snapshots.rs +5 -10
- package/src/rust/components/viewer/wiring.rs +1 -21
- package/src/rust/components/viewer.rs +15 -10
- package/src/rust/components/window_editor.rs +8 -9
- package/src/rust/config/column_config_schema.rs +358 -52
- package/src/rust/config/datetime_column_style.rs +4 -21
- package/src/rust/config/mod.rs +0 -2
- package/src/rust/config/number_string_format.rs +211 -18
- package/src/rust/config/workspace_config.rs +2 -1
- package/src/rust/custom_elements/debug_plugin.rs +1 -10
- package/src/rust/custom_elements/mod.rs +0 -3
- package/src/rust/custom_elements/viewer.rs +0 -18
- package/src/rust/js/plugin.rs +0 -86
- package/src/rust/lib.rs +12 -15
- package/src/rust/presentation/column_locator.rs +3 -7
- package/src/rust/presentation.rs +85 -38
- package/src/rust/queries/hosted_tables.rs +38 -0
- package/src/rust/queries/mod.rs +2 -0
- package/src/rust/queries/palette_set.rs +1 -1
- package/src/rust/queries/plugin_column_styles.rs +2 -2
- package/src/rust/renderer/activate.rs +1 -3
- package/src/rust/renderer/dispatch.rs +117 -30
- package/src/rust/renderer/limits.rs +24 -5
- package/src/rust/renderer/plugin_config.rs +56 -8
- package/src/rust/renderer/props.rs +2 -1
- package/src/rust/renderer.rs +14 -27
- package/src/rust/session/props.rs +4 -3
- package/src/rust/session/view_subscription.rs +19 -6
- package/src/rust/session.rs +38 -70
- package/src/rust/tasks/create_panel.rs +1 -1
- package/src/rust/tasks/dismiss_render_warning.rs +1 -1
- package/src/rust/tasks/eject.rs +1 -0
- package/src/rust/tasks/pipeline.rs +0 -60
- package/src/rust/tasks/presize_panels.rs +24 -1
- package/src/rust/tasks/restore_and_render.rs +0 -17
- package/src/rust/tasks/send_column_config.rs +1 -1
- package/src/rust/tasks/send_plugin_config.rs +1 -1
- package/src/rust/tasks/set_edit_mode.rs +1 -1
- package/src/rust/ui/containers/control_group.rs +113 -0
- package/src/rust/{components → ui}/containers/dropdown_menu.rs +5 -2
- package/src/rust/{components → ui}/containers/mod.rs +1 -4
- package/src/rust/{components → ui}/containers/scroll_panel.rs +0 -22
- package/src/rust/{components → ui}/containers/scroll_panel_item.rs +0 -13
- package/src/rust/{components → ui}/containers/select.rs +8 -8
- package/src/rust/{components → ui}/containers/sidebar.rs +5 -32
- package/src/rust/{components → ui}/containers/split_panel.rs +8 -80
- package/src/rust/{components → ui}/containers/tab_list.rs +15 -9
- package/src/rust/{components → ui}/context_menu.rs +8 -13
- package/src/rust/{presentation/drag_helpers.rs → ui/dragdrop.rs} +26 -31
- package/src/rust/{components → ui}/font_loader.rs +0 -26
- package/src/rust/{components → ui}/form/color_selector.rs +4 -2
- package/src/rust/ui/form/intl_label.rs +81 -0
- package/src/rust/{components → ui}/form/mirrored_textarea.rs +0 -53
- package/src/rust/{components → ui}/form/mod.rs +1 -10
- package/src/rust/{components → ui}/form/multi_stop_gradient_selector.rs +4 -5
- package/src/rust/{components → ui}/form/named_value_picker.rs +1 -6
- package/src/rust/{components → ui}/form/number_field.rs +1 -1
- package/src/rust/{components → ui}/form/number_range_field.rs +1 -1
- package/src/rust/{components → ui}/form/optional_field.rs +3 -1
- package/src/rust/{components → ui}/form/palette_selector.rs +4 -5
- package/src/rust/{components → ui}/form/select_enum_field.rs +2 -2
- package/src/rust/{components → ui}/form/select_value_field.rs +2 -2
- package/src/rust/ui/mod.rs +56 -0
- package/src/rust/ui/modal.rs +61 -0
- package/src/rust/{components → ui}/portal.rs +174 -79
- package/src/rust/{components/style/style_provider.rs → ui/style.rs} +4 -34
- package/src/rust/utils/completion.rs +0 -6
- package/src/rust/{config/css_scale.rs → utils/css.rs} +38 -35
- package/src/rust/utils/mod.rs +2 -0
- package/src/rust/workspace.rs +35 -0
- package/src/svg/boolean-type.svg +3 -2
- package/src/svg/checkbox-checked-icon.svg +4 -7
- package/src/svg/checkbox-hover.svg +3 -3
- package/src/svg/checkbox-off.svg +2 -3
- package/src/svg/checkbox-on.svg +3 -3
- package/src/svg/checkbox-unchecked-icon.svg +3 -3
- package/src/svg/datagrid-select-column.svg +8 -15
- package/src/svg/datagrid-select-region.svg +8 -15
- package/src/svg/datagrid-select-row-tree.svg +7 -12
- package/src/svg/datagrid-select-row.svg +8 -13
- package/src/svg/date-type.svg +4 -23
- package/src/svg/drawer-tab-hover.svg +4 -6
- package/src/svg/drawer-tab-invert-hover.svg +5 -5
- package/src/svg/drawer-tab-invert.svg +3 -5
- package/src/svg/drawer-tab.svg +5 -5
- package/src/svg/mega-menu-icons-candlestick.svg +5 -37
- package/src/svg/mega-menu-icons-ohlc.svg +4 -39
- package/src/svg/mega-menu-icons-sunburst.svg +4 -38
- package/src/svg/mega-menu-icons-treemap.svg +3 -43
- package/src/svg/mega-menu-icons-y-scatter.svg +12 -72
- package/src/svg/new-panel-icon.svg +4 -0
- package/src/svg/number-type.svg +3 -3
- package/src/svg/radio-hover.svg +3 -3
- package/src/svg/radio-off.svg +3 -3
- package/src/svg/radio-on.svg +3 -3
- package/src/svg/status_ok.svg +3 -26
- package/src/svg/string-type.svg +4 -8
- package/src/svg/theme-icon.svg +5 -5
- package/src/themes/blueprint.css +133 -0
- package/src/themes/botanical.css +3 -52
- package/src/themes/defaults.css +3 -144
- package/src/themes/dracula.css +1 -71
- package/src/themes/eggplant.css +131 -0
- package/src/themes/gruvbox-dark.css +2 -79
- package/src/themes/gruvbox.css +2 -40
- package/src/themes/icons.css +2 -10
- package/src/themes/intl/ar.css +185 -0
- package/src/themes/intl/de.css +65 -33
- package/src/themes/intl/es.css +60 -28
- package/src/themes/intl/fr.css +60 -28
- package/src/themes/intl/ja.css +62 -30
- package/src/themes/intl/pt.css +58 -26
- package/src/themes/intl/zh.css +68 -36
- package/src/themes/intl.css +42 -7
- package/src/themes/ledger.css +137 -0
- package/src/themes/monokai.css +1 -64
- package/src/themes/nord.css +131 -0
- package/src/themes/phosphor.css +1 -61
- package/src/themes/pro-dark.css +1 -52
- package/src/themes/pro.css +98 -0
- package/src/themes/solarized-dark.css +1 -46
- package/src/themes/solarized.css +1 -24
- package/src/themes/themes.css +10 -5
- package/src/themes/vaporwave.css +1 -57
- package/src/themes/velvet.css +132 -0
- package/src/ts/column-format.ts +52 -2
- package/src/ts/extensions.ts +0 -13
- package/src/ts/ts-rs/ViewOnUpdateResp.ts +1 -1
- package/src/css/plugin-settings-panel.css +0 -99
- package/src/rust/components/modal.rs +0 -177
- package/src/rust/custom_elements/copy_dropdown.rs +0 -219
- package/src/rust/custom_elements/export_dropdown.rs +0 -216
- package/src/rust/custom_elements/modal.rs +0 -299
- package/src/svg/dropdown-selector-light.svg +0 -3
- /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-39c3c3b28e3cbd48 → perspective-viewer-adc6f3f79141112b}/inline5.js +0 -0
- /package/src/css/{containers → ui/containers}/scroll-panel.css +0 -0
- /package/src/css/{containers → ui/containers}/split-panel.css +0 -0
- /package/src/css/{dom → ui/dom}/checkbox.css +0 -0
- /package/src/css/{dom → ui/dom}/scrollbar.css +0 -0
- /package/src/css/{form → ui/form}/mirrored-textarea.css +0 -0
- /package/src/rust/components/{form → code_editor}/highlight.rs +0 -0
- /package/src/rust/{components → ui}/containers/sidebar_close_button.rs +0 -0
- /package/src/rust/{components → ui}/form/number_input.rs +0 -0
|
@@ -166,13 +166,14 @@ pub async fn presize_visible_panels_open(
|
|
|
166
166
|
pub async fn presize_visible_panels_pane_width(
|
|
167
167
|
workspace: &Workspace,
|
|
168
168
|
elem: &web_sys::HtmlElement,
|
|
169
|
+
pane_sel: &str,
|
|
169
170
|
pane_width: f64,
|
|
170
171
|
) -> StagedPresents {
|
|
171
172
|
let Some(mpc) = shadow_rect(elem, "#main_panel_container") else {
|
|
172
173
|
return StagedPresents::default();
|
|
173
174
|
};
|
|
174
175
|
|
|
175
|
-
let Some(pane) = shadow_rect(elem,
|
|
176
|
+
let Some(pane) = shadow_rect(elem, pane_sel) else {
|
|
176
177
|
return StagedPresents::default();
|
|
177
178
|
};
|
|
178
179
|
|
|
@@ -308,6 +309,28 @@ fn shadow_rect(elem: &web_sys::HtmlElement, sel: &str) -> Option<web_sys::DomRec
|
|
|
308
309
|
)
|
|
309
310
|
}
|
|
310
311
|
|
|
312
|
+
/// The width the `SplitPanel` pane at `pane_sel` takes with no divider
|
|
313
|
+
/// override, measured under one forced synchronous layout that no paint or
|
|
314
|
+
/// `ResizeObserver` can observe, or `None` when the pane isn't in the DOM.
|
|
315
|
+
pub fn measure_pane_natural_width(elem: &web_sys::HtmlElement, pane_sel: &str) -> Option<f64> {
|
|
316
|
+
let pane = elem
|
|
317
|
+
.shadow_root()?
|
|
318
|
+
.query_selector(pane_sel)
|
|
319
|
+
.ok()??
|
|
320
|
+
.dyn_into::<web_sys::HtmlElement>()
|
|
321
|
+
.ok()?;
|
|
322
|
+
|
|
323
|
+
let style = pane.style();
|
|
324
|
+
let css_text = style.css_text();
|
|
325
|
+
let class_name = pane.class_name();
|
|
326
|
+
style.set_css_text("");
|
|
327
|
+
let _ = pane.class_list().remove_1("is-width-override");
|
|
328
|
+
let width = pane.get_bounding_client_rect().width();
|
|
329
|
+
style.set_css_text(&css_text);
|
|
330
|
+
pane.set_class_name(&class_name);
|
|
331
|
+
Some(width)
|
|
332
|
+
}
|
|
333
|
+
|
|
311
334
|
/// The open-state geometry deltas cached for the next settings *open* (P2):
|
|
312
335
|
/// `(layout_area.w − mpc.w, main_column.h − mpc.h)`. Only meaningful while the
|
|
313
336
|
/// settings pane is open (i.e. measured at close time).
|
|
@@ -10,10 +10,6 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
//! Apply a full [`ViewerConfigUpdate`] (settings, theme, title, plugin,
|
|
14
|
-
//! plugin_config, columns_config, view_config) and re-draw, on the snapshot
|
|
15
|
-
//! pipeline (see `tasks/pipeline.rs` / `SESSION_CONFIG_COHERENCE_PLAN.md`).
|
|
16
|
-
|
|
17
13
|
use futures::Future;
|
|
18
14
|
use perspective_client::clone;
|
|
19
15
|
|
|
@@ -28,19 +24,6 @@ use crate::*;
|
|
|
28
24
|
/// Apply a full [`ViewerConfigUpdate`] (theme, title, plugin selection,
|
|
29
25
|
/// plugin config, columns config, view config) to the engines and re-draw.
|
|
30
26
|
/// Returns an [`ApiFuture<()>`] which resolves when the draw completes.
|
|
31
|
-
///
|
|
32
|
-
/// `origin` says who initiated the restore ([`RunOrigin`]): a `Public`
|
|
33
|
-
/// element-API call keeps the no-op-restore refresh affordance (an
|
|
34
|
-
/// `Unchanged` reconcile still repaints via `update`); an `Internal`
|
|
35
|
-
/// restore that reconciles `Unchanged` and changes no plugin state
|
|
36
|
-
/// dispatches nothing.
|
|
37
|
-
///
|
|
38
|
-
/// This function owns the PRE-LOCK prologue only (element-level settings /
|
|
39
|
-
/// title / host-theme mirror, plugin resolution, the synchronous config
|
|
40
|
-
/// commit and spinner token); the run itself is
|
|
41
|
-
/// [`locked_run`] with the caller's `task` awaited inside the lock. The
|
|
42
|
-
/// `update`'s `table` field is NOT applied here — table binding is the
|
|
43
|
-
/// `task`'s job (see `restore_panel` / `table_lifecycle`).
|
|
44
27
|
pub fn restore_and_render(
|
|
45
28
|
session: &Session,
|
|
46
29
|
renderer: &Renderer,
|
|
@@ -49,7 +49,7 @@ pub fn send_column_config(
|
|
|
49
49
|
|
|
50
50
|
clone!(session);
|
|
51
51
|
renderer
|
|
52
|
-
.update_lazy(async move { Ok(session.
|
|
52
|
+
.update_lazy(async move { Ok(session.get_view_with_dimensions()) })
|
|
53
53
|
.await?;
|
|
54
54
|
renderer.column_style_changed.emit(columns_configs);
|
|
55
55
|
Ok(())
|
|
@@ -44,7 +44,7 @@ pub fn send_plugin_config(session: &Session, renderer: &Renderer, update: Column
|
|
|
44
44
|
.restore(&plugin_token, Some(&columns_configs))?;
|
|
45
45
|
clone!(session);
|
|
46
46
|
renderer
|
|
47
|
-
.update_lazy(async move { Ok(session.
|
|
47
|
+
.update_lazy(async move { Ok(session.get_view_with_dimensions()) })
|
|
48
48
|
.await?;
|
|
49
49
|
renderer.plugin_config_changed.emit(plugin_config);
|
|
50
50
|
}
|
|
@@ -51,7 +51,7 @@ pub fn set_edit_mode(session: &Session, renderer: &Renderer, mode: &str) {
|
|
|
51
51
|
.restore(&plugin_token, Some(&columns_configs))?;
|
|
52
52
|
clone!(session);
|
|
53
53
|
renderer
|
|
54
|
-
.update_lazy(async move { Ok(session.
|
|
54
|
+
.update_lazy(async move { Ok(session.get_view_with_dimensions()) })
|
|
55
55
|
.await?;
|
|
56
56
|
renderer.plugin_config_changed.emit(plugin_config);
|
|
57
57
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
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 wasm_bindgen::JsCast;
|
|
14
|
+
use web_sys::{Event, MouseEvent};
|
|
15
|
+
use yew::{
|
|
16
|
+
Callback, Html, Properties, function_component, html, use_callback, use_effect_with,
|
|
17
|
+
use_mut_ref, use_node_ref,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
use crate::ui::form::intl_label::IntlLabel;
|
|
21
|
+
|
|
22
|
+
#[derive(Properties, PartialEq)]
|
|
23
|
+
pub struct ControlGroupProps {
|
|
24
|
+
pub group_key: String,
|
|
25
|
+
|
|
26
|
+
pub open: bool,
|
|
27
|
+
|
|
28
|
+
pub on_toggle: Callback<(String, bool)>,
|
|
29
|
+
|
|
30
|
+
pub children: Html,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[function_component]
|
|
34
|
+
pub fn ControlGroup(props: &ControlGroupProps) -> Html {
|
|
35
|
+
let ontoggle = use_callback(
|
|
36
|
+
(props.group_key.clone(), props.on_toggle.clone()),
|
|
37
|
+
|event: Event, (group_key, on_toggle)| {
|
|
38
|
+
if let Some(el) = event
|
|
39
|
+
.target()
|
|
40
|
+
.and_then(|x| x.dyn_into::<web_sys::Element>().ok())
|
|
41
|
+
{
|
|
42
|
+
on_toggle.emit((group_key.clone(), el.has_attribute("open")));
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
let onclick = use_callback((), |event: MouseEvent, _| {
|
|
48
|
+
if !event.shift_key() {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
event.prevent_default();
|
|
53
|
+
let Some(details) = event
|
|
54
|
+
.target()
|
|
55
|
+
.and_then(|x| x.dyn_into::<web_sys::Element>().ok())
|
|
56
|
+
.and_then(|x| x.closest("details.control-group").ok().flatten())
|
|
57
|
+
else {
|
|
58
|
+
return;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
let Some(scope) = details.closest(".tab-section").ok().flatten() else {
|
|
62
|
+
return;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
let expand = !details.has_attribute("open");
|
|
66
|
+
let Ok(groups) = scope.query_selector_all("details.control-group") else {
|
|
67
|
+
return;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
for i in 0..groups.length() {
|
|
71
|
+
let Some(el) = groups
|
|
72
|
+
.item(i)
|
|
73
|
+
.and_then(|x| x.dyn_into::<web_sys::Element>().ok())
|
|
74
|
+
else {
|
|
75
|
+
continue;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if expand {
|
|
79
|
+
let _ = el.set_attribute("open", "");
|
|
80
|
+
} else {
|
|
81
|
+
let _ = el.remove_attribute("open");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
let details_ref = use_node_ref();
|
|
87
|
+
{
|
|
88
|
+
let details_ref = details_ref.clone();
|
|
89
|
+
use_effect_with(
|
|
90
|
+
(props.group_key.clone(), props.on_toggle.clone()),
|
|
91
|
+
move |(group_key, on_toggle)| {
|
|
92
|
+
let group_key = group_key.clone();
|
|
93
|
+
let on_toggle = on_toggle.clone();
|
|
94
|
+
move || {
|
|
95
|
+
if let Some(el) = details_ref.cast::<web_sys::Element>() {
|
|
96
|
+
on_toggle.emit((group_key, el.has_attribute("open")));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let open = *use_mut_ref(|| props.open).borrow();
|
|
104
|
+
html! {
|
|
105
|
+
<details ref={details_ref} class="control-group" {open} {ontoggle}>
|
|
106
|
+
<summary {onclick}>
|
|
107
|
+
<span class="control-group-chevron shift-alt-icon" />
|
|
108
|
+
<IntlLabel name={props.group_key.clone()} group=true />
|
|
109
|
+
</summary>
|
|
110
|
+
{ props.children.clone() }
|
|
111
|
+
</details>
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -27,6 +27,7 @@ where
|
|
|
27
27
|
pub callback: Callback<T>,
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/// A clickable item list, optionally grouped (`DropDownMenuItem::OptGroup`).
|
|
30
31
|
pub struct DropDownMenu<T>
|
|
31
32
|
where
|
|
32
33
|
T: Into<Html> + Clone + PartialEq + 'static,
|
|
@@ -64,7 +65,9 @@ where
|
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
html! {
|
|
67
|
-
<span onmousedown={click} class="
|
|
68
|
+
<span onmousedown={click} class="dropdown-menu-item">
|
|
69
|
+
{ x.clone().into() }
|
|
70
|
+
</span>
|
|
68
71
|
}
|
|
69
72
|
},
|
|
70
73
|
DropDownMenuItem::OptGroup(name, xs) => {
|
|
@@ -78,7 +81,7 @@ where
|
|
|
78
81
|
move |_: MouseEvent| value.clone()
|
|
79
82
|
});
|
|
80
83
|
html! {
|
|
81
|
-
<span onmousedown={ click }>
|
|
84
|
+
<span onmousedown={ click } class="dropdown-menu-item">
|
|
82
85
|
{ x.clone().into() }
|
|
83
86
|
</span>
|
|
84
87
|
}
|
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
//! `Component` types.
|
|
15
|
-
|
|
16
|
-
pub mod dragdrop_list;
|
|
13
|
+
pub mod control_group;
|
|
17
14
|
pub mod dropdown_menu;
|
|
18
15
|
pub mod scroll_panel;
|
|
19
16
|
pub mod scroll_panel_item;
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
// Forked from https://github.com/AircastDev/yew-virtual-scroller (Apache 2.0)
|
|
14
|
-
// Adds support for Yew 0.19, auto-width and a simplified message structure.
|
|
15
|
-
|
|
16
13
|
use std::ops::Range;
|
|
17
14
|
use std::rc::Rc;
|
|
18
15
|
|
|
@@ -67,8 +64,6 @@ pub struct ScrollPanelProps {
|
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
impl ScrollPanelProps {
|
|
70
|
-
/// Calculate the total virtual height of this scroll panel from the `size`
|
|
71
|
-
/// prop of its children.
|
|
72
67
|
fn total_height(&self) -> f64 {
|
|
73
68
|
self.children
|
|
74
69
|
.iter()
|
|
@@ -148,8 +143,6 @@ impl Component for ScrollPanel {
|
|
|
148
143
|
self.calculate_window_content(ctx)
|
|
149
144
|
},
|
|
150
145
|
|
|
151
|
-
// TODO don't hardcode pixel offsets - fix the CSS container to not
|
|
152
|
-
// require pixel offsets to work.
|
|
153
146
|
ScrollPanelMsg::UpdateViewportDimensions => {
|
|
154
147
|
let viewport = self.viewport_elem(ctx);
|
|
155
148
|
let rect = viewport.get_bounding_client_rect();
|
|
@@ -174,9 +167,6 @@ impl Component for ScrollPanel {
|
|
|
174
167
|
}
|
|
175
168
|
}
|
|
176
169
|
|
|
177
|
-
/// If the new total row height is different than last time this component
|
|
178
|
-
/// was rendered, we need to double-render to read the container's
|
|
179
|
-
/// potentially updated height.
|
|
180
170
|
fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
|
|
181
171
|
let total_height = ctx.props().total_height();
|
|
182
172
|
self.needs_rerender =
|
|
@@ -213,8 +203,6 @@ impl Component for ScrollPanel {
|
|
|
213
203
|
]
|
|
214
204
|
});
|
|
215
205
|
|
|
216
|
-
// TODO This glitches - we should use the `sticky` positioning strategy that
|
|
217
|
-
// `regular-table` uses.
|
|
218
206
|
html! {
|
|
219
207
|
<div
|
|
220
208
|
ref={self.viewport(ctx)}
|
|
@@ -306,16 +294,6 @@ impl ScrollPanel {
|
|
|
306
294
|
.map(|x| x.0)
|
|
307
295
|
.unwrap_or_default();
|
|
308
296
|
|
|
309
|
-
// Why is this `end_node + 2`, I can see you asking yourself? `end_node` is the
|
|
310
|
-
// index of the last visible child, but [`Range`] is an open interval so we must
|
|
311
|
-
// increment by 1. The next rendered element is always occluded by the parent
|
|
312
|
-
// container, it may seem unnecessary to render it, however not doing so causing
|
|
313
|
-
// scroll glitching in Chrome:
|
|
314
|
-
// * When the first pixel of the `end_node + 1` child is scrolled into view, the
|
|
315
|
-
// container element it is embedded in will expand past the end of the scroll
|
|
316
|
-
// container.
|
|
317
|
-
// * Chrome detects this and helpfully scrolls this new element into view,
|
|
318
|
-
// re-triggering the on scroll callback.
|
|
319
297
|
let visible_range = start_node..ctx.props().children.len().min(end_node + 2);
|
|
320
298
|
let content_window = Some(ContentWindow {
|
|
321
299
|
scroll_top,
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
// Forked from https://github.com/AircastDev/yew-virtual-scroller (Apache 2.0)
|
|
14
|
-
// Adds support for Yew 0.19, auto-width and a simplified message structure.
|
|
15
|
-
|
|
16
13
|
use std::cell::Cell;
|
|
17
14
|
use std::rc::Rc;
|
|
18
15
|
|
|
@@ -22,21 +19,11 @@ use yew::prelude::*;
|
|
|
22
19
|
pub struct ScrollPanelItemProps {
|
|
23
20
|
pub children: Children,
|
|
24
21
|
|
|
25
|
-
/// The expected size of this component in pixels. Calculating this value
|
|
26
|
-
/// ahead of time makes it easier to implement a high-performance virtual
|
|
27
|
-
/// renderer without resorting to weird tricks, _but_ checking that this
|
|
28
|
-
/// hint is correct is nearly as expensive. So, we only generate the
|
|
29
|
-
/// validation code in debug builds.
|
|
30
22
|
pub size_hint: f64,
|
|
31
23
|
|
|
32
|
-
/// Should we measure the child sizes or just rely on the hint? This
|
|
33
|
-
/// option may be enabled during debugging to validation render optimization
|
|
34
|
-
/// via [`Self::size_hint`], but will faile tests due to the extra DOM
|
|
35
|
-
/// structure it emits.
|
|
36
24
|
#[prop_or_default]
|
|
37
25
|
pub is_debug_mode: bool,
|
|
38
26
|
|
|
39
|
-
/// Communicate the panel size to virtual parent
|
|
40
27
|
#[prop_or_default]
|
|
41
28
|
measured_size: Rc<Cell<Option<f64>>>,
|
|
42
29
|
}
|
|
@@ -88,10 +88,6 @@ where
|
|
|
88
88
|
true
|
|
89
89
|
},
|
|
90
90
|
|
|
91
|
-
// All the up and down arrow keys to instantly select, which is
|
|
92
|
-
// useful for keyboard warrios. This is not ada without the shift
|
|
93
|
-
// key. I'm not sure if it is _with_ the shift key either, but its
|
|
94
|
-
// cool.
|
|
95
91
|
SelectMsg::KeyboardInput(is_shift, idx, code) => {
|
|
96
92
|
if is_shift {
|
|
97
93
|
if code.as_str() == "ArrowUp" {
|
|
@@ -114,13 +110,11 @@ where
|
|
|
114
110
|
}
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
// The `<select>` has its own state not refelcted by `SelectProps`.
|
|
118
113
|
fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
|
|
119
114
|
self.selected = ctx.props().selected.clone();
|
|
120
115
|
true
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
// Annoyingly, `<select>` cannot be updated from its HTML alone.
|
|
124
118
|
fn rendered(&mut self, _ctx: &Context<Self>, _first_render: bool) {
|
|
125
119
|
if let Some(elem) = self.select_ref.cast::<web_sys::HtmlSelectElement>() {
|
|
126
120
|
elem.set_value(&format!("{}", self.selected))
|
|
@@ -230,9 +224,15 @@ where
|
|
|
230
224
|
<label>
|
|
231
225
|
{ ctx.props().label.as_ref().map(|x| x.to_string()).unwrap_or_default() }
|
|
232
226
|
</label>
|
|
233
|
-
<div class={wrapper_class} data-value={value}>
|
|
227
|
+
<div class={wrapper_class} data-value={value}>
|
|
228
|
+
{ select }
|
|
229
|
+
<span class="select-arrow" />
|
|
230
|
+
</div>
|
|
234
231
|
} else {
|
|
235
|
-
<div class={wrapper_class} data-value={value}>
|
|
232
|
+
<div class={wrapper_class} data-value={value}>
|
|
233
|
+
{ select }
|
|
234
|
+
<span class="select-arrow" />
|
|
235
|
+
</div>
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
}
|
|
@@ -19,38 +19,25 @@ use yew::{
|
|
|
19
19
|
use_node_ref,
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
use crate::components::containers::sidebar_close_button::SidebarCloseButton;
|
|
23
|
-
use crate::components::editable_header::{EditableHeader, EditableHeaderProps};
|
|
24
22
|
use crate::js::{ResizeObserver, ResizeObserverEntry};
|
|
23
|
+
use crate::ui::containers::sidebar_close_button::SidebarCloseButton;
|
|
25
24
|
|
|
26
25
|
#[derive(PartialEq, Clone, Properties)]
|
|
27
26
|
pub struct SidebarProps {
|
|
28
|
-
/// The component's children.
|
|
29
27
|
pub children: Children,
|
|
30
28
|
|
|
31
|
-
/// When this callback is called, the sidebar will close
|
|
32
29
|
pub on_close: Callback<()>,
|
|
33
30
|
pub id_prefix: String,
|
|
34
31
|
pub width_override: Option<i32>,
|
|
35
32
|
pub selected_tab: Option<usize>,
|
|
36
|
-
pub
|
|
37
|
-
|
|
38
|
-
/// Trap-door width shared across this sidebar's tabs: the lifted
|
|
39
|
-
/// running max of the widths this component reports through
|
|
40
|
-
/// `on_auto_width`. Held by the parent (ultimately
|
|
41
|
-
/// `PerspectiveViewer`'s geometry state, like the settings panel's
|
|
42
|
-
/// Query/Plugin/Debug trap-door) so it survives tab switches AND
|
|
43
|
-
/// sidebar re-mounts, and clears on divider reset.
|
|
33
|
+
pub header: Html,
|
|
34
|
+
|
|
44
35
|
#[prop_or_default]
|
|
45
36
|
pub auto_width: f64,
|
|
46
37
|
|
|
47
|
-
/// Fires with the sidebar's rendered width after each render; the
|
|
48
|
-
/// owner keeps the running max threaded back as `auto_width`.
|
|
49
38
|
#[prop_or_default]
|
|
50
39
|
pub on_auto_width: Callback<f64>,
|
|
51
40
|
|
|
52
|
-
/// Pinned state for the header's pin toggle; the button renders only
|
|
53
|
-
/// when `on_toggle_pin` is provided.
|
|
54
41
|
#[prop_or_default]
|
|
55
42
|
pub is_pinned: bool,
|
|
56
43
|
|
|
@@ -58,23 +45,12 @@ pub struct SidebarProps {
|
|
|
58
45
|
pub on_toggle_pin: Option<Callback<()>>,
|
|
59
46
|
}
|
|
60
47
|
|
|
61
|
-
/// Sidebars are designed to live in a
|
|
62
|
-
/// [`super::split_panel::SplitPanel`]
|
|
48
|
+
/// Sidebars are designed to live in a `SplitPanel`.
|
|
63
49
|
#[function_component]
|
|
64
50
|
pub fn Sidebar(p: &SidebarProps) -> Html {
|
|
65
51
|
let id = &p.id_prefix;
|
|
66
52
|
let noderef = use_node_ref();
|
|
67
53
|
|
|
68
|
-
// The trap-door reports the sidebar's rendered width to its owner via
|
|
69
|
-
// a `ResizeObserver` on the sidebar element, NOT a render effect:
|
|
70
|
-
// width changes are driven by DOM mutations anywhere in the tab
|
|
71
|
-
// subtree (e.g. the window editor staging a long column name into a
|
|
72
|
-
// slot), which need not re-render this component at all. The observer
|
|
73
|
-
// sees every one. `contentRect` (not the border box) is load-bearing:
|
|
74
|
-
// the sizer below is a content child, so ratcheting the border box
|
|
75
|
-
// would feed any sidebar padding back into unbounded growth. A manual
|
|
76
|
-
// divider drag (`width_override`) disables the ratchet until the
|
|
77
|
-
// divider resets.
|
|
78
54
|
let live_props = use_mut_ref(|| (Callback::<f64>::default(), None::<i32>));
|
|
79
55
|
*live_props.borrow_mut() = (p.on_auto_width.clone(), p.width_override);
|
|
80
56
|
use_effect_with((), {
|
|
@@ -139,10 +115,7 @@ pub fn Sidebar(p: &SidebarProps) -> Html {
|
|
|
139
115
|
<>
|
|
140
116
|
<SidebarCloseButton id={format!("{id}_close_button")} on_close_sidebar={&p.on_close} />
|
|
141
117
|
<div class="sidebar_column" id={format!("{id}_sidebar")} ref={noderef}>
|
|
142
|
-
<div class="sidebar_header">
|
|
143
|
-
<EditableHeader ..p.header_props.clone() />
|
|
144
|
-
{ pin_button }
|
|
145
|
-
</div>
|
|
118
|
+
<div class="sidebar_header">{ p.header.clone() }{ pin_button }</div>
|
|
146
119
|
<div class="sidebar_border" id={format!("{id}_border")} />
|
|
147
120
|
{ p.children.iter().collect::<Html>() }
|
|
148
121
|
<div class="sidebar-auto-width" style={width_style} />
|