Improve the Data panel's data display with monospaced text and copyable number values (#4040)

* Improve the Data panel's data display with monospaced text and copyable number values

* Revert attempted fix for dropdown menus appearing lower in scrolled Properties panel, since it makes other floating menus freeze the app

* Code review
This commit is contained in:
Keavon Chambers 2026-04-23 15:32:18 -07:00 committed by GitHub
parent e2117d9a02
commit fcf9396a71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 74 additions and 32 deletions

View File

@ -362,6 +362,7 @@ pub struct TextAreaInput {
pub value: String, pub value: String,
pub label: Option<String>, pub label: Option<String>,
pub disabled: bool, pub disabled: bool,
pub monospace: bool,
// Tooltips // Tooltips
#[serde(rename = "tooltipLabel")] #[serde(rename = "tooltipLabel")]

View File

@ -584,7 +584,7 @@ impl TableRowLayout for f64 {
"Number (f64)".to_string() "Number (f64)".to_string()
} }
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> { fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let widgets = vec![TextLabel::new(self.to_string()).widget_instance()]; let widgets = vec![NumberInput::new(Some(*self)).disabled(true).max_width(220).display_decimal_places(20).widget_instance()];
vec![LayoutGroup::row(widgets)] vec![LayoutGroup::row(widgets)]
} }
} }
@ -597,7 +597,7 @@ impl TableRowLayout for u32 {
"Number (u32)".to_string() "Number (u32)".to_string()
} }
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> { fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let widgets = vec![TextLabel::new(self.to_string()).widget_instance()]; let widgets = vec![NumberInput::new(Some(*self as f64)).disabled(true).max_width(220).display_decimal_places(20).widget_instance()];
vec![LayoutGroup::row(widgets)] vec![LayoutGroup::row(widgets)]
} }
} }
@ -610,7 +610,8 @@ impl TableRowLayout for u64 {
"Number (u64)".to_string() "Number (u64)".to_string()
} }
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> { fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let widgets = vec![TextLabel::new(self.to_string()).widget_instance()]; // TODO: Make this robust for large u64 values that don't fit in f64 (above roughly 2^53). Perhaps using a bigint kind of approach through the widget's data flow.
let widgets = vec![NumberInput::new(Some(*self as f64)).disabled(true).max_width(220).display_decimal_places(20).widget_instance()];
vec![LayoutGroup::row(widgets)] vec![LayoutGroup::row(widgets)]
} }
} }
@ -642,7 +643,7 @@ impl TableRowLayout for String {
} }
} }
fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> { fn element_page(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
let widgets = vec![TextAreaInput::new(self.to_string()).disabled(true).widget_instance()]; let widgets = vec![TextAreaInput::new(self.to_string()).monospace(true).disabled(true).widget_instance()];
vec![LayoutGroup::row(widgets)] vec![LayoutGroup::row(widgets)]
} }
} }

View File

@ -2355,7 +2355,12 @@ pub mod choice {
.map(|(item, metadata)| { .map(|(item, metadata)| {
let updater = updater_factory(); let updater = updater_factory();
let committer = committer_factory(); let committer = committer_factory();
MenuListEntry::new(metadata.name).label(metadata.label).on_update(move |_| updater(item)).on_commit(committer) MenuListEntry::new(metadata.name)
.label(metadata.label)
.tooltip_label(metadata.label)
.tooltip_description(metadata.description.unwrap_or_default())
.on_update(move |_| updater(item))
.on_commit(committer)
}) })
.collect() .collect()
}) })

View File

@ -261,9 +261,27 @@
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 1; line-height: 1;
tab-size: 4;
color: var(--color-e-nearwhite); color: var(--color-e-nearwhite);
} }
body,
textarea,
input {
&::selection {
background-color: var(--color-4-dimgray);
// Target only Safari
@supports (background: -webkit-named-image(i)) {
& {
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
// https://stackoverflow.com/a/71753552/775283
background-color: rgba(var(--color-4-dimgray-rgb), calc(254 / 255));
}
}
}
}
svg, svg,
img { img {
display: block; display: block;

View File

@ -54,11 +54,16 @@
.widget-span:has(.text-area-input) { .widget-span:has(.text-area-input) {
flex: 1 1 100%; flex: 1 1 100%;
.text-area-input textarea { .text-area-input {
height: 100%; margin: 0;
margin-top: 0; padding: 4px 0;
margin-bottom: 0;
resize: none; textarea {
height: 100%;
margin-top: 0;
margin-bottom: 0;
resize: none;
}
} }
} }
} }

View File

@ -519,7 +519,7 @@
style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0} style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0}
data-tooltip-label={nodeNameTooltipLabel(node)} data-tooltip-label={nodeNameTooltipLabel(node)}
data-tooltip-description={` data-tooltip-description={`
${(description || "").trim()}${editor.inDevelopmentMode() ? `\n\nID: ${node.id}. Position: (${node.position[0]}, ${node.position[1]}).` : ""} ${(description || "").trim()}${editor.inDevelopmentMode() ? `\n\n*ID: ${node.id}. Position: (${node.position[0]}, ${node.position[1]}).*` : ""}
`.trim()} `.trim()}
data-node={node.id} data-node={node.id}
> >
@ -682,7 +682,7 @@
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`} style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
data-tooltip-label={nodeNameTooltipLabel(node)} data-tooltip-label={nodeNameTooltipLabel(node)}
data-tooltip-description={` data-tooltip-description={`
${(description || "").trim()}${editor.inDevelopmentMode() ? `\n\nID: ${node.id}. Position: (${node.position[0]}, ${node.position[1]}).` : ""} ${(description || "").trim()}${editor.inDevelopmentMode() ? `\n\n*ID: ${node.id}. Position: (${node.position[0]}, ${node.position[1]}).*` : ""}
`.trim()} `.trim()}
data-node={node.id} data-node={node.id}
> >

View File

@ -12,11 +12,31 @@
export let tooltipShortcut: ActionShortcut | undefined = undefined; export let tooltipShortcut: ActionShortcut | undefined = undefined;
// Callbacks // Callbacks
export let action: (index: number) => void; export let action: (index: number) => void;
function truncate(label: string): string {
let maxLength = 40;
if (label.length <= maxLength) return label;
let truncated = label;
const hasQuotes = label.startsWith(`"`) && label.endsWith(`"`);
if (hasQuotes) {
truncated = label.slice(1, -1);
maxLength -= 2;
}
truncated = truncated.slice(0, maxLength - 1) + "…";
if (hasQuotes) truncated = `"${truncated}"`;
return truncated;
}
</script> </script>
<LayoutRow class="breadcrumb-trail-buttons" {tooltipLabel} {tooltipDescription} {tooltipShortcut}> <LayoutRow class="breadcrumb-trail-buttons" {tooltipLabel} {tooltipDescription} {tooltipShortcut}>
{#each labels as label, index} {#each labels as label, index}
<TextButton {label} emphasized={index === labels.length - 1} {disabled} action={() => !disabled && index !== labels.length - 1 && action(index)} /> <TextButton label={truncate(label)} emphasized={index === labels.length - 1} {disabled} action={() => !disabled && index !== labels.length - 1 && action(index)} />
{/each} {/each}
</LayoutRow> </LayoutRow>

View File

@ -22,6 +22,7 @@
export let label: string | undefined = undefined; export let label: string | undefined = undefined;
export let spellcheck = false; export let spellcheck = false;
export let disabled = false; export let disabled = false;
export let monospace = false;
export let narrow = false; export let narrow = false;
export let textarea = false; export let textarea = false;
export let tooltipLabel: string | undefined = undefined; export let tooltipLabel: string | undefined = undefined;
@ -75,7 +76,7 @@
</script> </script>
<!-- This is a base component, extended by others like NumberInput and TextInput. It should not be used directly. --> <!-- This is a base component, extended by others like NumberInput and TextInput. It should not be used directly. -->
<LayoutRow class={`field-input ${className}`} classes={{ disabled, narrow, ...classes }} style={styleName} {styles} {tooltipLabel} {tooltipDescription} {tooltipShortcut}> <LayoutRow class={`field-input ${className}`} classes={{ disabled, narrow, monospace, ...classes }} style={styleName} {styles} {tooltipLabel} {tooltipDescription} {tooltipShortcut}>
{#if !textarea} {#if !textarea}
<input <input
type="text" type="text"
@ -133,6 +134,13 @@
--widget-height: 20px; --widget-height: 20px;
} }
&.monospace {
input,
textarea {
font-family: "Source Code Pro", monospace;
}
}
label { label {
flex: 0 0 auto; flex: 0 0 auto;
line-height: calc(var(--widget-height) - 6px); line-height: calc(var(--widget-height) - 6px);
@ -163,19 +171,6 @@
color: var(--color-e-nearwhite); color: var(--color-e-nearwhite);
caret-color: var(--color-e-nearwhite); caret-color: var(--color-e-nearwhite);
unicode-bidi: plaintext; unicode-bidi: plaintext;
&::selection {
background-color: var(--color-4-dimgray);
// Target only Safari
@supports (background: -webkit-named-image(i)) {
& {
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
// https://stackoverflow.com/a/71753552/775283
background-color: rgba(var(--color-4-dimgray-rgb), calc(254 / 255));
}
}
}
} }
input { input {
@ -210,11 +205,6 @@
textarea { textarea {
color: var(--color-8-uppergray); color: var(--color-8-uppergray);
} }
input {
// Disables drag-selecting the text, since `user-select: none` doesn't work for input elements
pointer-events: none;
}
} }
} }
</style> </style>

View File

@ -11,6 +11,7 @@
export let tooltipDescription: string | undefined = undefined; export let tooltipDescription: string | undefined = undefined;
export let tooltipShortcut: ActionShortcut | undefined = undefined; export let tooltipShortcut: ActionShortcut | undefined = undefined;
export let disabled = false; export let disabled = false;
export let monospace = false;
let self: FieldInput | undefined; let self: FieldInput | undefined;
let editing = false; let editing = false;
@ -57,6 +58,7 @@
spellcheck={true} spellcheck={true}
{label} {label}
{disabled} {disabled}
{monospace}
{tooltipLabel} {tooltipLabel}
{tooltipDescription} {tooltipDescription}
{tooltipShortcut} {tooltipShortcut}