From c75c6c9695242c4d2d2794cf31480d508164f42d Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 8 Aug 2026 01:45:53 -0700 Subject: [PATCH] Fix read-only widget appearance and focus, and keep ColorInput picks surviving a layout diff (#4423) --- .../color_picker_message_handler.rs | 33 ++++++++++++++++--- .../messages/layout/layout_message_handler.rs | 8 +++-- .../widgets/buttons/TextButton.svelte | 2 +- .../widgets/inputs/CheckboxInput.svelte | 1 - .../widgets/inputs/DropdownInput.svelte | 2 +- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/color_picker/color_picker_message_handler.rs b/editor/src/messages/color_picker/color_picker_message_handler.rs index b74013a6c6..03d055a31b 100644 --- a/editor/src/messages/color_picker/color_picker_message_handler.rs +++ b/editor/src/messages/color_picker/color_picker_message_handler.rs @@ -615,7 +615,11 @@ impl ColorPickerMessageHandler { // Hex groups.push(LayoutGroup::row(vec![ - TextLabel::new("Hex").tooltip_label("Hex Color Code").tooltip_description(HEX_DESCRIPTION).widget_instance(), + TextLabel::new("Hex") + .disabled(self.disabled) + .tooltip_label("Hex Color Code") + .tooltip_description(HEX_DESCRIPTION) + .widget_instance(), Separator::new(SeparatorStyle::Related).widget_instance(), TextInput::new(hex_value) .centered(true) @@ -628,7 +632,11 @@ impl ColorPickerMessageHandler { // RGB groups.push(LayoutGroup::row(vec![ - TextLabel::new("RGB").tooltip_label("Red/Green/Blue").tooltip_description("Integers 0–255.").widget_instance(), + TextLabel::new("RGB") + .disabled(self.disabled) + .tooltip_label("Red/Green/Blue") + .tooltip_description("Integers 0–255.") + .widget_instance(), Separator::new(SeparatorStyle::Related).widget_instance(), rgb_input(RgbChannel::Red, rgb_255.map(|(r, _, _)| r), "Red Channel", self.disabled), Separator::new(SeparatorStyle::Related).widget_instance(), @@ -640,6 +648,7 @@ impl ColorPickerMessageHandler { // HSV groups.push(LayoutGroup::row(vec![ TextLabel::new("HSV") + .disabled(self.disabled) .tooltip_label("Hue/Saturation/Value") .tooltip_description("Also known as Hue/Saturation/Brightness (HSB), but distinct from Hue/Saturation/Lightness (HSL), a different color model.") .widget_instance(), @@ -677,7 +686,11 @@ impl ColorPickerMessageHandler { // Alpha groups.push(LayoutGroup::row(vec![ - TextLabel::new("Alpha").tooltip_label("Alpha").tooltip_description(ALPHA_DESCRIPTION).widget_instance(), + TextLabel::new("Alpha") + .disabled(self.disabled) + .tooltip_label("Alpha") + .tooltip_description(ALPHA_DESCRIPTION) + .widget_instance(), Separator::new(SeparatorStyle::Related).widget_instance(), NumberInput::new(if self.is_none { None } else { Some(self.alpha * 100.) }) .disabled(self.disabled) @@ -698,7 +711,11 @@ impl ColorPickerMessageHandler { let entries = RadioEntryData::list_from_choice_type(|gradient_spread| ColorPickerMessage::SetGradientSpread { gradient_spread }.into()); groups.push(LayoutGroup::row(vec![ - TextLabel::new("Ends").tooltip_label("Gradient Spread / Cyclic").tooltip_description(ENDS_DESCRIPTION).widget_instance(), + TextLabel::new("Ends") + .disabled(self.disabled) + .tooltip_label("Gradient Spread / Cyclic") + .tooltip_description(ENDS_DESCRIPTION) + .widget_instance(), Separator::new(SeparatorStyle::Related).widget_instance(), RadioInput::new(entries) .narrow(true) @@ -727,6 +744,7 @@ impl ColorPickerMessageHandler { groups.push(LayoutGroup::row(vec![ TextLabel::new("Intrp.") + .disabled(self.disabled) .tooltip_label("Gradient Interpolation") .tooltip_description(INTERPOLATION_DESCRIPTION) .widget_instance(), @@ -745,7 +763,11 @@ impl ColorPickerMessageHandler { let entries = MenuListEntry::sections_from_choice_type(|gradient_space| ColorPickerMessage::SetGradientSpace { gradient_space }.into()); groups.push(LayoutGroup::row(vec![ - TextLabel::new("Space").tooltip_label("Gradient Space").tooltip_description(SPACE_DESCRIPTION).widget_instance(), + TextLabel::new("Space") + .disabled(self.disabled) + .tooltip_label("Gradient Space") + .tooltip_description(SPACE_DESCRIPTION) + .widget_instance(), Separator::new(SeparatorStyle::Related).widget_instance(), DropdownInput::new(entries) .selected_index(Some(self.gradient_space as u32)) @@ -762,6 +784,7 @@ impl ColorPickerMessageHandler { groups.push(LayoutGroup::row(vec![ TextLabel::new("Arc") + .disabled(self.disabled) .tooltip_label("Gradient Hue Direction") .tooltip_description(HUE_DIRECTION_DESCRIPTION) .widget_instance(), diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index 9df6018b8b..2224994b95 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -201,8 +201,12 @@ impl LayoutMessageHandler { warn!("ColorInput update was not able to be parsed as FillChoice: {color_button:?}"); return; }; - color_button.value = fill_choice; - (color_button.on_update.callback)(color_button) + // The stored copy has to keep mirroring what the frontend was last sent, so the rebuilt layout still + // diffs against it and syncs picks that leave the swatch unchanged; the callback borrows the new one + let previous_value = std::mem::replace(&mut color_button.value, fill_choice); + let update_message = (color_button.on_update.callback)(color_button); + color_button.value = previous_value; + update_message } }; diff --git a/frontend/src/components/widgets/buttons/TextButton.svelte b/frontend/src/components/widgets/buttons/TextButton.svelte index e239b04dd8..cda8938547 100644 --- a/frontend/src/components/widgets/buttons/TextButton.svelte +++ b/frontend/src/components/widgets/buttons/TextButton.svelte @@ -75,7 +75,7 @@ data-emphasized={emphasized || undefined} data-disabled={disabled || undefined} data-text-button - tabindex={disabled ? -1 : 0} + tabindex={disabled ? -1 : undefined} data-floating-menu-spawner data-block-hover-transfer={menuListChildrenExists ? undefined : ""} on:click={onClick} diff --git a/frontend/src/components/widgets/inputs/CheckboxInput.svelte b/frontend/src/components/widgets/inputs/CheckboxInput.svelte index e550c245de..566e72e48b 100644 --- a/frontend/src/components/widgets/inputs/CheckboxInput.svelte +++ b/frontend/src/components/widgets/inputs/CheckboxInput.svelte @@ -54,7 +54,6 @@ dispatch("checked", inputElement?.checked || false); }} {disabled} - tabindex={disabled ? -1 : 0} bind:this={inputElement} />