Settings: an accent palette folds inside a narrow box
The accent picker's palette takes what the custom well leaves and folds its swatches; a test puts twelve presets in a 280px box and asserts they fold under each other inside it. The settings tests split their appearance cases into a file of their own. AGENTS says editing takes the owner's handler itself.
This commit is contained in:
1 parent
195f9964a0
commit
8e4d1f7785
5 files changed
+81
-43
No files matched your search
@@ -168,7 +168,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
|
||||
- A box that shows a host's picture takes the picture's shape from the host (`ratio`), so nothing is cropped and a point given as a share lands on the picture. A focusable one keeps its focus border on an outer box, so the picture keeps that shape exactly (`media::ImageCropper`).
|
||||
- A default only the component can work out, such as a crop fitted to a picture it decodes, reaches the owner once through `window.defer` after render (`media::ImageUpload`).
|
||||
- A ScrubInput shows its number in about 140px beside a short label. In a narrower column a pair hides it, so a long label takes a row of its own (`canvas::TypographyPanel`).
|
||||
- Design panels edit a whole value and hand the owner a changed copy through `canvas::panel::editing`. A swatch that opens a picker is `canvas::panel::color_well`.
|
||||
- Design panels edit a whole value and hand the owner a changed copy through `canvas::panel::editing`, which takes the owner's handler itself: a component without one fails at render. A swatch that opens a picker is `canvas::panel::color_well`.
|
||||
- A press that stops propagation also stops the ancestors' focus on press. A layer that takes keys focuses itself in its own press handler (`canvas::ToolLayer`, `canvas::MindMap`), and a field over it stops its own presses.
|
||||
- A button inside a pressable row goes through `lists::row_action`, which keeps its press and its Space or Enter from the row (`devtools::ConnectionManager`).
|
||||
- A field opened over a component hands focus back to that component on Enter and Escape, through `forms::Editing`'s `returning` and `give_back` (`canvas::writing`); a blur keeps the words and leaves focus where it went.
|
||||
|
||||
@@ -398,3 +398,4 @@ Per-component lines live in `tasks/`. Tags there:
|
||||
| T34 | 1 | FAIL | a focused tile's Left and Right, and the guard that leaves arrows to a focused control inside a card, untested |
|
||||
| T34 | 2 | PASS | |
|
||||
| T35 | 1 | FAIL | a row's control kept its full width past a 280px box; a notice's name shrank to nothing; privacy, notices and startup dropped edits with no handler; Apply's and the reset's rest and a box turned off untested |
|
||||
| T35 | 2 | FAIL | an accent picker of nine or more presets still ran past a 280px box |
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
App, ElementId, Hsla, IntoElement, ParentElement, Pixels, RenderOnce, SharedString, Styled,
|
||||
Window, div,
|
||||
App, ElementId, Hsla, InteractiveElement, IntoElement, ParentElement, Pixels, RenderOnce,
|
||||
SharedString, Styled, Window, div,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -140,14 +140,17 @@ impl RenderOnce for AccentColorPicker {
|
||||
};
|
||||
let columns = u16::try_from(self.presets.len()).expect("a handful of presets");
|
||||
div()
|
||||
.debug_selector(|| "accent-color-picker".into())
|
||||
.flex()
|
||||
.items_start()
|
||||
.gap_2()
|
||||
.child(
|
||||
ColorPalette::new((self.id.clone(), "presets"), self.presets)
|
||||
.columns(columns)
|
||||
.selected(self.color)
|
||||
.on_change(report(picked)),
|
||||
div().flex_1().min_w_0().child(
|
||||
ColorPalette::new((self.id.clone(), "presets"), self.presets)
|
||||
.columns(columns)
|
||||
.selected(self.color)
|
||||
.on_change(report(picked)),
|
||||
),
|
||||
)
|
||||
.child(color_well(
|
||||
(self.id, "custom").into(),
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
use gpui::{
|
||||
AnyElement, App, Entity, IntoElement, ParentElement, Styled, TestAppContext, Window, div, hsla,
|
||||
px,
|
||||
};
|
||||
|
||||
use super::{Desk, desk, said, say, tab, tap};
|
||||
use crate::settings::{AccentColorPicker, FontSizeControl};
|
||||
|
||||
fn accent(_: &mut Window, _: &mut App, owner: Entity<Desk>) -> AnyElement {
|
||||
let (red, blue) = (hsla(0.0, 0.6, 0.5, 1.0), hsla(0.6, 0.6, 0.5, 1.0));
|
||||
AccentColorPicker::new("accent", red, [("Red", red), ("Blue", blue)])
|
||||
.on_change(move |color, _, cx| say(&owner, format!("blue {}", color == blue), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the presets, Red then Blue, then the custom well.
|
||||
#[gpui::test]
|
||||
fn a_preset_sets_the_accent(cx: &mut TestAppContext) {
|
||||
let (host, cx) = desk(accent, cx);
|
||||
tab(2, cx);
|
||||
tap("space", cx);
|
||||
assert_eq!(said(&host, cx), ["blue true"]);
|
||||
}
|
||||
|
||||
fn default_size(_: &mut Window, _: &mut App, owner: Entity<Desk>) -> AnyElement {
|
||||
FontSizeControl::new("size", 14.0, 14.0, (12.0, 24.0))
|
||||
.on_change(move |size, _, cx| say(&owner, format!("size {size}"), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// At the default size the way back rests, so the second stop wraps to the slider.
|
||||
#[gpui::test]
|
||||
fn the_way_back_rests_at_the_default_size(cx: &mut TestAppContext) {
|
||||
let (host, cx) = desk(default_size, cx);
|
||||
tab(2, cx);
|
||||
tap("space", cx);
|
||||
assert!(said(&host, cx).is_empty());
|
||||
}
|
||||
|
||||
fn many_presets(_: &mut Window, _: &mut App, _: Entity<Desk>) -> AnyElement {
|
||||
let presets: Vec<(String, gpui::Hsla)> = (0..12)
|
||||
.map(|ix| (format!("hue {ix}"), hsla(ix as f32 / 12.0, 0.5, 0.5, 1.0)))
|
||||
.collect();
|
||||
div()
|
||||
.w(px(280.0))
|
||||
.child(AccentColorPicker::new("accent", presets[0].1, presets).on_change(|_, _, _| {}))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Twelve swatches do not fit in one 280px row, so they fold under each other inside the box.
|
||||
#[gpui::test]
|
||||
fn many_presets_fold_inside_a_narrow_box(cx: &mut TestAppContext) {
|
||||
let (_, cx) = desk(many_presets, cx);
|
||||
let picker = cx.debug_bounds("accent-color-picker").expect("the picker");
|
||||
assert!(
|
||||
picker.size.width <= px(280.0),
|
||||
"no wider than its box: {picker:?}"
|
||||
);
|
||||
assert!(
|
||||
picker.size.height > px(40.0),
|
||||
"its swatches fold to a second row: {picker:?}"
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
use gpui::{
|
||||
AnyElement, App, Context, Entity, IntoElement, KeyBinding, ParentElement, Render, Styled,
|
||||
TestAppContext, VisualTestContext, Window, div, hsla, px,
|
||||
TestAppContext, VisualTestContext, Window, div, px,
|
||||
};
|
||||
|
||||
use super::{
|
||||
AccentColorPicker, Appearance, Changed, DeveloperModeToggle, FeatureFlags, Flag,
|
||||
FontSizeControl, ImportExportSettings, Notices, NotificationSettings, Privacy, PrivacySettings,
|
||||
Proxy, ProxySettings, ResetToDefault, SettingEntry, SettingsLayout, SettingsSearch, Stage,
|
||||
Startup, StartupSettings, StorageSettings, Store, ThemeSelector,
|
||||
Appearance, Changed, DeveloperModeToggle, FeatureFlags, Flag, FontSizeControl,
|
||||
ImportExportSettings, Notices, NotificationSettings, Privacy, PrivacySettings, Proxy,
|
||||
ProxySettings, ResetToDefault, SettingEntry, SettingsLayout, SettingsSearch, Stage, Startup,
|
||||
StartupSettings, StorageSettings, Store, ThemeSelector,
|
||||
};
|
||||
use crate::{
|
||||
forms::{self, Choice, TextInput},
|
||||
@@ -306,22 +306,6 @@ fn the_arrows_open_the_next_section(cx: &mut TestAppContext) {
|
||||
assert_eq!(said(&host, cx), ["open b"]);
|
||||
}
|
||||
|
||||
fn accent(_: &mut Window, _: &mut App, owner: Entity<Desk>) -> AnyElement {
|
||||
let (red, blue) = (hsla(0.0, 0.6, 0.5, 1.0), hsla(0.6, 0.6, 0.5, 1.0));
|
||||
AccentColorPicker::new("accent", red, [("Red", red), ("Blue", blue)])
|
||||
.on_change(move |color, _, cx| say(&owner, format!("blue {}", color == blue), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the presets, Red then Blue, then the custom well.
|
||||
#[gpui::test]
|
||||
fn a_preset_sets_the_accent(cx: &mut TestAppContext) {
|
||||
let (host, cx) = desk(accent, cx);
|
||||
tab(2, cx);
|
||||
tap("space", cx);
|
||||
assert_eq!(said(&host, cx), ["blue true"]);
|
||||
}
|
||||
|
||||
fn privacy(_: &mut Window, _: &mut App, owner: Entity<Desk>) -> AnyElement {
|
||||
let privacy = Privacy {
|
||||
telemetry: true,
|
||||
@@ -455,21 +439,6 @@ fn apply_rests_while_the_port_is_bad(cx: &mut TestAppContext) {
|
||||
assert!(said(&host, cx).is_empty());
|
||||
}
|
||||
|
||||
fn default_size(_: &mut Window, _: &mut App, owner: Entity<Desk>) -> AnyElement {
|
||||
FontSizeControl::new("size", 14.0, 14.0, (12.0, 24.0))
|
||||
.on_change(move |size, _, cx| say(&owner, format!("size {size}"), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// At the default size the way back rests, so the second stop wraps to the slider.
|
||||
#[gpui::test]
|
||||
fn the_way_back_rests_at_the_default_size(cx: &mut TestAppContext) {
|
||||
let (host, cx) = desk(default_size, cx);
|
||||
tab(2, cx);
|
||||
tap("space", cx);
|
||||
assert!(said(&host, cx).is_empty());
|
||||
}
|
||||
|
||||
/// Stops: Do not disturb, then App, which is on.
|
||||
#[gpui::test]
|
||||
fn a_box_pressed_off_lets_its_pair_go(cx: &mut TestAppContext) {
|
||||
@@ -478,3 +447,5 @@ fn a_box_pressed_off_lets_its_pair_go(cx: &mut TestAppContext) {
|
||||
tap("space", cx);
|
||||
assert_eq!(said(&host, cx), ["[] false"]);
|
||||
}
|
||||
|
||||
mod appearance;
|
||||
Reference in new issue
Block a user