@perspective-dev/viewer 5.1.0 → 5.3.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 +9 -9
- 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/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/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/docs/perspective-docs.json +1 -0
- package/dist/esm/column-format.d.ts +19 -28
- package/dist/esm/perspective-viewer.d.ts +3 -0
- package/dist/esm/perspective-viewer.inline.js +9 -9
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +9 -9
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/plugin.d.ts +10 -0
- package/dist/esm/providers.d.ts +79 -0
- package/dist/esm/ts-rs/CompactDisplay.d.ts +5 -0
- package/dist/esm/ts-rs/CurrencyCode.d.ts +1 -0
- package/dist/esm/ts-rs/CurrencyDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/CurrencyNumberFormatStyle.d.ts +8 -0
- package/dist/esm/ts-rs/CurrencySign.d.ts +1 -0
- package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +1 -0
- package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +54 -0
- package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +34 -0
- package/dist/esm/ts-rs/DatetimeColorMode.d.ts +1 -0
- package/dist/esm/ts-rs/DatetimeFormatType.d.ts +6 -0
- package/dist/esm/ts-rs/FormatMode.d.ts +1 -0
- package/dist/esm/ts-rs/FormatUnit.d.ts +1 -0
- package/dist/esm/ts-rs/Notation.d.ts +17 -0
- package/dist/esm/ts-rs/NumberFormatStyle.d.ts +18 -0
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +42 -2
- package/dist/esm/ts-rs/PluginStaticConfig.d.ts +35 -0
- package/dist/esm/ts-rs/RestoreOptions.d.ts +19 -0
- package/dist/esm/ts-rs/RoundingMode.d.ts +1 -0
- package/dist/esm/ts-rs/RoundingPriority.d.ts +1 -0
- package/dist/esm/ts-rs/SaveWorkspaceOptions.d.ts +10 -0
- package/dist/esm/ts-rs/SignDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +1 -0
- package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +24 -0
- package/dist/esm/ts-rs/SplitRollupMode.d.ts +9 -0
- package/dist/esm/ts-rs/StringColorMode.d.ts +1 -0
- package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/Unit.d.ts +1 -0
- package/dist/esm/ts-rs/UnitDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/UnitNumberFormatStyle.d.ts +6 -0
- package/dist/esm/ts-rs/UseGrouping.d.ts +1 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +42 -2
- package/dist/esm/ts-rs/ViewerConfigInitial.d.ts +175 -0
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +63 -0
- package/dist/esm/ts-rs/WindowSpec.d.ts +3 -2
- package/dist/esm/ts-rs/WorkspaceConfig.d.ts +9 -1
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +20 -9
- package/dist/wasm/perspective-viewer.d.ts +157 -41
- package/dist/wasm/perspective-viewer.js +452 -151
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +22 -17
- package/package.json +2 -1
- package/src/css/_viewer_bundle.css +1 -0
- package/src/css/column-selector.css +8 -0
- package/src/css/column-settings-panel.css +9 -5
- package/src/css/column-style.css +209 -31
- package/src/css/config-selector.css +38 -3
- package/src/css/dom/select.css +2 -1
- package/src/css/form/code-editor.css +6 -7
- package/src/css/form/mirrored-textarea.css +81 -0
- package/src/css/viewer.css +328 -0
- package/src/rust/agent/client/mod.rs +19 -0
- package/src/rust/agent/client/protocol.rs +320 -0
- package/src/rust/agent/client/transport.rs +287 -0
- package/src/rust/agent/client/turn.rs +174 -0
- package/src/rust/agent/config.rs +159 -0
- package/src/rust/agent/docs.rs +293 -0
- package/src/rust/agent/markdown/block.rs +509 -0
- package/src/rust/agent/markdown/entity.rs +52 -0
- package/src/rust/agent/markdown/events.rs +71 -0
- package/src/rust/agent/markdown/inline.rs +497 -0
- package/src/rust/agent/markdown/mod.rs +466 -0
- package/src/rust/agent/mod.rs +23 -0
- package/src/rust/agent/preamble.md +16 -0
- package/src/rust/agent/runtime.rs +201 -0
- package/src/rust/agent/slot.rs +236 -0
- package/src/rust/agent/tools.rs +1141 -0
- package/src/rust/components/chat_panel.rs +289 -0
- package/src/rust/components/column_selector/active_column.rs +2 -2
- package/src/rust/components/column_selector/add_expression_button.rs +3 -3
- package/src/rust/components/column_selector/aggregate_selector.rs +2 -3
- package/src/rust/components/column_selector/config_selector.rs +84 -7
- package/src/rust/components/column_selector/expr_edit_button.rs +4 -10
- package/src/rust/components/column_selector/inactive_column.rs +2 -2
- package/src/rust/components/column_selector.rs +55 -4
- package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +293 -126
- package/src/rust/components/column_settings_sidebar/style_tab.rs +262 -225
- package/src/rust/components/column_settings_sidebar.rs +88 -69
- package/src/rust/components/containers/dragdrop_list.rs +37 -0
- package/src/rust/components/editable_header.rs +85 -144
- package/src/rust/components/expression_editor.rs +9 -16
- package/src/rust/components/form/code_editor.rs +29 -28
- package/src/rust/components/form/debug.rs +9 -5
- package/src/rust/components/form/mirrored_textarea.rs +165 -0
- package/src/rust/components/form/mod.rs +4 -1
- package/src/rust/components/form/multi_stop_gradient_selector.rs +476 -0
- package/src/rust/components/form/named_value_picker.rs +86 -0
- package/src/rust/components/form/palette_selector.rs +440 -0
- package/src/rust/components/main_panel/msg.rs +2 -2
- package/src/rust/components/main_panel/reconcile.rs +4 -4
- package/src/rust/components/mod.rs +2 -0
- package/src/rust/components/plugin_tab.rs +4 -28
- package/src/rust/components/settings_panel.rs +105 -22
- package/src/rust/components/viewer/msg.rs +46 -7
- package/src/rust/components/viewer/panels.rs +17 -20
- package/src/rust/components/viewer/render.rs +10 -3
- package/src/rust/components/viewer/settings.rs +163 -23
- package/src/rust/components/viewer/snapshots.rs +46 -21
- package/src/rust/components/viewer/wiring.rs +14 -25
- package/src/rust/components/viewer.rs +12 -8
- package/src/rust/components/window_editor.rs +75 -103
- package/src/rust/config/column_config_schema.rs +100 -41
- package/src/rust/config/css_scale.rs +882 -0
- package/src/rust/config/datetime_column_style/custom.rs +17 -0
- package/src/rust/config/datetime_column_style/simple.rs +10 -0
- package/src/rust/config/mod.rs +2 -0
- package/src/rust/config/number_string_format.rs +33 -0
- package/src/rust/config/options.rs +28 -0
- package/src/rust/config/plugin_static_config.rs +120 -5
- package/src/rust/config/viewer_config.rs +216 -3
- package/src/rust/config/workspace_config.rs +138 -10
- package/src/rust/custom_elements/viewer.rs +369 -119
- package/src/rust/custom_events.rs +43 -1
- package/src/rust/js/regular_layout.rs +3 -3
- package/src/rust/lib.rs +15 -0
- package/src/rust/presentation/column_locator.rs +19 -5
- package/src/rust/presentation.rs +200 -36
- package/src/rust/queries/column_locator.rs +74 -44
- package/src/rust/queries/get_viewer_config.rs +2 -1
- package/src/rust/queries/mod.rs +2 -0
- package/src/rust/queries/palette_set.rs +82 -0
- package/src/rust/queries/plugin_column_styles.rs +6 -2
- package/src/rust/renderer/dispatch.rs +16 -4
- package/src/rust/renderer/plugin_config.rs +309 -47
- package/src/rust/renderer.rs +15 -42
- package/src/rust/session/column_defaults_update.rs +32 -7
- package/src/rust/session/metadata.rs +23 -21
- package/src/rust/session/props.rs +1 -0
- package/src/rust/session/replace_expression_update.rs +1 -0
- package/src/rust/session.rs +9 -6
- package/src/rust/tasks/create_panel.rs +46 -49
- package/src/rust/tasks/edit_expression.rs +19 -23
- package/src/rust/tasks/edit_window.rs +9 -11
- package/src/rust/tasks/eject.rs +4 -1
- package/src/rust/tasks/pipeline.rs +2 -2
- package/src/rust/tasks/presize_panels.rs +44 -5
- package/src/rust/tasks/reset_all.rs +4 -4
- package/src/rust/tasks/restore_and_render.rs +17 -44
- package/src/rust/tasks/restore_panel.rs +37 -22
- package/src/rust/tasks/set_edit_mode.rs +3 -1
- package/src/rust/tasks/sync_update_panels.rs +18 -24
- package/src/rust/tasks/update_theme.rs +23 -18
- package/src/rust/utils/css_vars.rs +26 -0
- package/src/rust/utils/mod.rs +2 -0
- package/src/rust/utils/spawn.rs +1 -1
- package/src/rust/workspace.rs +454 -199
- package/src/svg/lock.svg +7 -0
- package/src/themes/botanical.css +10 -0
- package/src/themes/defaults.css +12 -0
- package/src/themes/dracula.css +17 -0
- package/src/themes/gruvbox-dark.css +20 -0
- package/src/themes/gruvbox.css +10 -0
- package/src/themes/icons.css +1 -0
- package/src/themes/intl/de.css +16 -0
- package/src/themes/intl/es.css +16 -0
- package/src/themes/intl/fr.css +16 -0
- package/src/themes/intl/ja.css +16 -0
- package/src/themes/intl/pt.css +16 -0
- package/src/themes/intl/zh.css +16 -0
- package/src/themes/intl.css +16 -0
- package/src/themes/monokai.css +22 -0
- package/src/themes/phosphor.css +5 -0
- package/src/themes/pro-dark.css +10 -0
- package/src/themes/solarized-dark.css +7 -0
- package/src/themes/solarized.css +7 -0
- package/src/themes/vaporwave.css +20 -0
- package/src/ts/column-format.ts +67 -46
- package/src/ts/perspective-viewer.ts +3 -0
- package/src/ts/plugin.ts +14 -0
- package/src/ts/providers.ts +96 -0
- package/src/ts/ts-rs/CompactDisplay.ts +3 -0
- package/src/ts/ts-rs/CurrencyCode.ts +3 -0
- package/src/ts/ts-rs/CurrencyDisplay.ts +3 -0
- package/src/ts/ts-rs/CurrencyNumberFormatStyle.ts +6 -0
- package/src/ts/ts-rs/CurrencySign.ts +3 -0
- package/src/ts/ts-rs/CustomDatetimeFormat.ts +3 -0
- package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +54 -0
- package/src/ts/ts-rs/CustomNumberFormatConfig.ts +25 -0
- package/src/ts/ts-rs/DatetimeColorMode.ts +3 -0
- package/src/ts/ts-rs/DatetimeFormatType.ts +8 -0
- package/src/ts/ts-rs/FormatMode.ts +3 -0
- package/src/ts/ts-rs/FormatUnit.ts +3 -0
- package/src/ts/ts-rs/Notation.ts +11 -0
- package/src/ts/ts-rs/NumberFormatStyle.ts +12 -0
- package/src/ts/ts-rs/PanelViewerConfig.ts +48 -2
- package/src/ts/ts-rs/PluginStaticConfig.ts +36 -1
- package/src/ts/ts-rs/RestoreOptions.ts +20 -0
- package/src/ts/ts-rs/RoundingMode.ts +3 -0
- package/src/ts/ts-rs/RoundingPriority.ts +3 -0
- package/src/ts/ts-rs/SaveWorkspaceOptions.ts +11 -0
- package/src/ts/ts-rs/SignDisplay.ts +3 -0
- package/src/ts/ts-rs/SimpleDatetimeFormat.ts +3 -0
- package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +25 -0
- package/src/ts/ts-rs/SplitRollupMode.ts +11 -0
- package/src/ts/ts-rs/StringColorMode.ts +3 -0
- package/src/ts/ts-rs/TrailingZeroDisplay.ts +3 -0
- package/src/ts/ts-rs/Unit.ts +3 -0
- package/src/ts/ts-rs/UnitDisplay.ts +3 -0
- package/src/ts/ts-rs/UnitNumberFormatStyle.ts +5 -0
- package/src/ts/ts-rs/UseGrouping.ts +3 -0
- package/src/ts/ts-rs/ViewerConfig.ts +48 -2
- package/src/ts/ts-rs/ViewerConfigInitial.ts +164 -0
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +72 -2
- package/src/ts/ts-rs/WindowSpec.ts +3 -2
- package/src/ts/ts-rs/WorkspaceConfig.ts +8 -2
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +18 -9
- package/dist/esm/ts-rs/WindowAggregate.d.ts +0 -1
- package/src/rust/components/form/color_range_selector.rs +0 -137
- package/src/ts/ts-rs/WindowAggregate.ts +0 -3
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-39c3c3b28e3cbd48}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-39c3c3b28e3cbd48}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-39c3c3b28e3cbd48}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-39c3c3b28e3cbd48}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-39c3c3b28e3cbd48}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-39c3c3b28e3cbd48}/inline5.js +0 -0
|
@@ -18,6 +18,7 @@ use web_sys::*;
|
|
|
18
18
|
use yew::prelude::*;
|
|
19
19
|
|
|
20
20
|
use crate::components::form::highlight::highlight;
|
|
21
|
+
use crate::components::form::mirrored_textarea::MirroredTextarea;
|
|
21
22
|
use crate::components::function_dropdown::{FunctionDropDownElement, FunctionDropDownPortal};
|
|
22
23
|
use crate::exprtk::{Cursor, tokenize};
|
|
23
24
|
use crate::utils::*;
|
|
@@ -44,6 +45,9 @@ pub struct CodeEditorProps {
|
|
|
44
45
|
#[prop_or_default]
|
|
45
46
|
pub error: Option<ExprValidationError>,
|
|
46
47
|
|
|
48
|
+
#[prop_or_default]
|
|
49
|
+
pub contained: bool,
|
|
50
|
+
|
|
47
51
|
/// Selected theme name, threaded for PortalModal consumers.
|
|
48
52
|
#[prop_or_default]
|
|
49
53
|
pub theme: String,
|
|
@@ -164,40 +168,37 @@ pub fn code_editor(props: &CodeEditorProps) -> Html {
|
|
|
164
168
|
))
|
|
165
169
|
.collect::<Html>();
|
|
166
170
|
|
|
167
|
-
let
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
+
let mut outer_class = classes!("scrollable");
|
|
172
|
+
let mut inner_class = classes!("editor-inner", "scrollable");
|
|
173
|
+
|
|
174
|
+
if props.wordwrap {
|
|
175
|
+
outer_class.push("wordwrap");
|
|
176
|
+
inner_class.push("wordwrap");
|
|
171
177
|
};
|
|
178
|
+
|
|
179
|
+
if props.contained {
|
|
180
|
+
outer_class.push("contained")
|
|
181
|
+
}
|
|
182
|
+
|
|
172
183
|
clone!(props.disabled);
|
|
173
184
|
html! {
|
|
174
185
|
<>
|
|
175
|
-
<div id="editor" {
|
|
186
|
+
<div id="editor" class={outer_class}>
|
|
176
187
|
<div id="line_numbers" ref={lineno_ref}>{ line_numbers }</div>
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
<MirroredTextarea
|
|
189
|
+
id="textarea_editable"
|
|
190
|
+
mirror_id="content"
|
|
191
|
+
class={inner_class}
|
|
192
|
+
mirror={terms}
|
|
193
|
+
{textarea_ref}
|
|
194
|
+
mirror_ref={content_ref}
|
|
195
|
+
{disabled}
|
|
196
|
+
{oninput}
|
|
197
|
+
{onscroll}
|
|
198
|
+
{onkeydown}
|
|
199
|
+
>
|
|
188
200
|
<div id="editor-height-sizer" />
|
|
189
|
-
|
|
190
|
-
{ terms }
|
|
191
|
-
{ {
|
|
192
|
-
// A linebreak which pushs a textarea into scroll overflow
|
|
193
|
-
// may not necessarily do so in the `<pre>`, because there is
|
|
194
|
-
// no cursor when the last line has no content, so add
|
|
195
|
-
// some space here to make sure overlfow is in sync
|
|
196
|
-
// with the text area.
|
|
197
|
-
" "
|
|
198
|
-
} }
|
|
199
|
-
</pre>
|
|
200
|
-
</div>
|
|
201
|
+
</MirroredTextarea>
|
|
201
202
|
</div>
|
|
202
203
|
<FunctionDropDownPortal
|
|
203
204
|
element={(*portal_dropdown).clone()}
|
|
@@ -23,12 +23,14 @@ use crate::presentation::*;
|
|
|
23
23
|
use crate::renderer::*;
|
|
24
24
|
use crate::session::*;
|
|
25
25
|
use crate::utils::*;
|
|
26
|
+
use crate::workspace::Workspace;
|
|
26
27
|
|
|
27
28
|
#[derive(Clone, PartialEq, Properties)]
|
|
28
29
|
pub struct DebugPanelProps {
|
|
29
30
|
pub presentation: Presentation,
|
|
30
31
|
pub renderer: Renderer,
|
|
31
32
|
pub session: Session,
|
|
33
|
+
pub workspace: Workspace,
|
|
32
34
|
|
|
33
35
|
/// Trap-door width pinned by the parent `SettingsPanel` so switching
|
|
34
36
|
/// tabs doesn't shrink the panel. Threaded into the hidden sizer
|
|
@@ -176,6 +178,7 @@ pub fn debug_panel(props: &DebugPanelProps) -> Html {
|
|
|
176
178
|
<CodeEditor
|
|
177
179
|
expr={&*expr}
|
|
178
180
|
disabled=false
|
|
181
|
+
contained=true
|
|
179
182
|
{oninput}
|
|
180
183
|
{onsave}
|
|
181
184
|
select_all={select_all.subscriber()}
|
|
@@ -236,15 +239,16 @@ impl DebugPanelProps {
|
|
|
236
239
|
ApiFuture::spawn(async move {
|
|
237
240
|
match serde_json::from_str(&text) {
|
|
238
241
|
Ok(config) => {
|
|
239
|
-
|
|
242
|
+
let active =
|
|
243
|
+
props.workspace.active_renderer().as_ref() == Some(&props.renderer);
|
|
244
|
+
match crate::tasks::restore_panel(
|
|
240
245
|
&props.session,
|
|
241
246
|
&props.renderer,
|
|
242
247
|
&props.presentation,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
crate::tasks::RunOrigin::Public,
|
|
248
|
+
&props.workspace,
|
|
249
|
+
crate::tasks::RestoreMode::Existing { active },
|
|
246
250
|
config,
|
|
247
|
-
|
|
251
|
+
crate::tasks::RestoreErrors::Suppress,
|
|
248
252
|
)
|
|
249
253
|
.await
|
|
250
254
|
{
|
|
@@ -0,0 +1,165 @@
|
|
|
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
|
+
//! A `<textarea>` whose box is sized by its own text.
|
|
14
|
+
//!
|
|
15
|
+
//! A textarea cannot grow with its content — it scrolls at whatever height
|
|
16
|
+
//! it was given. The technique here, shared by [`CodeEditor`] and the chat
|
|
17
|
+
//! prompt, is to make the textarea a purely functional layer: it takes the
|
|
18
|
+
//! keystrokes, the selection and the caret, but paints no glyphs
|
|
19
|
+
//! (`color: transparent`). Underneath sits a `<pre>` mirror of the same
|
|
20
|
+
//! characters which IS painted and IS in flow, so the ordinary layout
|
|
21
|
+
//! engine sizes the box.
|
|
22
|
+
//!
|
|
23
|
+
//! This is deliberately not a JS measure-and-resize loop
|
|
24
|
+
//! (`scrollHeight` → inline `height`): that re-measures on a reflow it
|
|
25
|
+
//! just forced, drifts whenever font-size or the loaded font changes
|
|
26
|
+
//! without an `input` event to re-trigger it, and jitters at fractional
|
|
27
|
+
//! line heights. Here the two layers share their text metrics, so growth
|
|
28
|
+
//! is exact by construction and free at runtime.
|
|
29
|
+
//!
|
|
30
|
+
//! Consumers decide the AXES: the mirror's `white-space` governs growth,
|
|
31
|
+
//! so `pre-wrap` grows only downward (the chat prompt) while `pre` also
|
|
32
|
+
//! grows sideways (the expression editor). They also own the box —
|
|
33
|
+
//! padding, borders, min/max size — with `mirrored-textarea.css` fixing
|
|
34
|
+
//! only what MUST agree between the two layers.
|
|
35
|
+
//!
|
|
36
|
+
//! [`CodeEditor`]: super::code_editor::CodeEditor
|
|
37
|
+
|
|
38
|
+
use yew::html::IntoPropValue;
|
|
39
|
+
use yew::prelude::*;
|
|
40
|
+
|
|
41
|
+
#[derive(Clone)]
|
|
42
|
+
pub struct Mirror(pub Html);
|
|
43
|
+
|
|
44
|
+
impl PartialEq for Mirror {
|
|
45
|
+
fn eq(&self, _other: &Self) -> bool {
|
|
46
|
+
false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
impl IntoPropValue<Mirror> for Html {
|
|
51
|
+
fn into_prop_value(self) -> Mirror {
|
|
52
|
+
Mirror(self)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#[derive(Properties, PartialEq)]
|
|
57
|
+
pub struct MirroredTextareaProps {
|
|
58
|
+
/// `id` of the `<textarea>` itself — consumer CSS and tests key on it.
|
|
59
|
+
pub id: AttrValue,
|
|
60
|
+
|
|
61
|
+
/// The mirror's content: the same characters the textarea holds,
|
|
62
|
+
/// as plain text, or marked up (`CodeEditor` passes highlighted
|
|
63
|
+
/// spans). A stale mirror means a caret that drifts from the glyphs,
|
|
64
|
+
/// so this is re-rendered unconditionally — see [`Mirror`].
|
|
65
|
+
pub mirror: Mirror,
|
|
66
|
+
|
|
67
|
+
/// `id` of the mirror `<pre>`, for consumers that style it directly.
|
|
68
|
+
#[prop_or_default]
|
|
69
|
+
pub mirror_id: Option<AttrValue>,
|
|
70
|
+
|
|
71
|
+
/// Extra classes for the positioned container.
|
|
72
|
+
#[prop_or_default]
|
|
73
|
+
pub class: Classes,
|
|
74
|
+
|
|
75
|
+
#[prop_or_default]
|
|
76
|
+
pub textarea_ref: NodeRef,
|
|
77
|
+
|
|
78
|
+
#[prop_or_default]
|
|
79
|
+
pub mirror_ref: NodeRef,
|
|
80
|
+
|
|
81
|
+
/// The `placeholder` ATTRIBUTE, which exists for assistive tech: it
|
|
82
|
+
/// is painted transparent, because a CSS-`content` label cannot be
|
|
83
|
+
/// written into an attribute and so cannot be localized. The text a
|
|
84
|
+
/// sighted user reads comes from the mirror instead — see
|
|
85
|
+
/// [`Self::is_empty`].
|
|
86
|
+
#[prop_or_default]
|
|
87
|
+
pub placeholder: AttrValue,
|
|
88
|
+
|
|
89
|
+
/// Whether [`Self::mirror`] is empty, which the component cannot see
|
|
90
|
+
/// for itself (the mirror is opaque `Html`). Tags the mirror with
|
|
91
|
+
/// `is-empty` so a consumer's stylesheet can supply placeholder text
|
|
92
|
+
/// through `content`, and therefore through the intl label
|
|
93
|
+
/// mechanism, rather than through the untranslatable attribute.
|
|
94
|
+
#[prop_or_default]
|
|
95
|
+
pub is_empty: bool,
|
|
96
|
+
|
|
97
|
+
#[prop_or_default]
|
|
98
|
+
pub disabled: bool,
|
|
99
|
+
|
|
100
|
+
#[prop_or_default]
|
|
101
|
+
pub oninput: Callback<InputEvent>,
|
|
102
|
+
|
|
103
|
+
#[prop_or_default]
|
|
104
|
+
pub onkeydown: Callback<KeyboardEvent>,
|
|
105
|
+
|
|
106
|
+
#[prop_or_default]
|
|
107
|
+
pub onscroll: Callback<Event>,
|
|
108
|
+
|
|
109
|
+
/// Extra nodes inside the positioned container, e.g. `CodeEditor`'s
|
|
110
|
+
/// minimum-height sizer.
|
|
111
|
+
#[prop_or_default]
|
|
112
|
+
pub children: Children,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#[function_component]
|
|
116
|
+
pub fn MirroredTextarea(props: &MirroredTextareaProps) -> Html {
|
|
117
|
+
html! {
|
|
118
|
+
<div class={classes!("mirrored-textarea", props.class.clone())}>
|
|
119
|
+
// `scrollable` is the viewer's webkit scrollbar styling: the
|
|
120
|
+
// input layer scrolls wherever a consumer lets it (the
|
|
121
|
+
// expression editor syncs its `scrollTop` to the mirror and
|
|
122
|
+
// line numbers), and is inert where it does not (the chat
|
|
123
|
+
// prompt, whose wrapper scrolls instead).
|
|
124
|
+
<textarea
|
|
125
|
+
id={props.id.clone()}
|
|
126
|
+
ref={props.textarea_ref.clone()}
|
|
127
|
+
class="mirrored-textarea-input scrollable"
|
|
128
|
+
spellcheck="false"
|
|
129
|
+
placeholder={props.placeholder.clone()}
|
|
130
|
+
disabled={props.disabled}
|
|
131
|
+
oninput={props.oninput.clone()}
|
|
132
|
+
onkeydown={props.onkeydown.clone()}
|
|
133
|
+
onscroll={props.onscroll.clone()}
|
|
134
|
+
/>
|
|
135
|
+
{ props.children.iter().collect::<Html>() }
|
|
136
|
+
<pre
|
|
137
|
+
id={props.mirror_id.clone()}
|
|
138
|
+
ref={props.mirror_ref.clone()}
|
|
139
|
+
class={classes!(
|
|
140
|
+
"mirrored-textarea-mirror",
|
|
141
|
+
props.is_empty.then_some("is-empty"),
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
{ props.mirror.0.clone() }
|
|
145
|
+
// A trailing newline opens a line box in the textarea but
|
|
146
|
+
// not in the `<pre>` (which has no caret to place there),
|
|
147
|
+
// so the mirror would come up one line short exactly when
|
|
148
|
+
// the text is about to overflow. The space forces it.
|
|
149
|
+
{ " " }
|
|
150
|
+
</pre>
|
|
151
|
+
</div>
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#[cfg(test)]
|
|
156
|
+
mod tests {
|
|
157
|
+
use super::*;
|
|
158
|
+
|
|
159
|
+
#[test]
|
|
160
|
+
fn mirror_never_compares_equal() {
|
|
161
|
+
let mirror = Mirror(Html::default());
|
|
162
|
+
assert!(mirror != mirror.clone());
|
|
163
|
+
assert!(Mirror(Html::default()) != Mirror(Html::default()));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -17,13 +17,16 @@
|
|
|
17
17
|
//! parent module directly.
|
|
18
18
|
|
|
19
19
|
pub mod code_editor;
|
|
20
|
-
pub mod color_range_selector;
|
|
21
20
|
pub mod color_selector;
|
|
22
21
|
pub mod debug;
|
|
22
|
+
pub mod mirrored_textarea;
|
|
23
|
+
pub mod multi_stop_gradient_selector;
|
|
24
|
+
pub mod named_value_picker;
|
|
23
25
|
pub mod number_field;
|
|
24
26
|
pub mod number_input;
|
|
25
27
|
pub mod number_range_field;
|
|
26
28
|
pub mod optional_field;
|
|
29
|
+
pub mod palette_selector;
|
|
27
30
|
pub mod select_enum_field;
|
|
28
31
|
pub mod select_value_field;
|
|
29
32
|
|