diff --git a/crates/ui-egui/src/canvas/proto_canvas.rs b/crates/ui-egui/src/canvas/proto_canvas.rs index b6955e956..3d7727f2c 100644 --- a/crates/ui-egui/src/canvas/proto_canvas.rs +++ b/crates/ui-egui/src/canvas/proto_canvas.rs @@ -171,6 +171,11 @@ fn target_at(app: &FigApp, doc: &Document, page: NodeId, source: NodeId, p: Pos2 if let Some(w) = siblings.into_iter().rev().find(|w| doc.world_bounds(*w).is_some_and(|b| b.contains(pt))) { return (w != v).then_some(Target::ChangeTo(w)); } + // The set's own background: nothing, as in Figma, whatever holds the set. (A set in a + // group has no top-level frame, so the fallback below would offer a section around it.) + if doc.world_bounds(set).is_some_and(|b| b.contains(pt)) { + return None; + } } frame_at(app, doc, page, p).filter(|f| doc.top_level_frame(source) != Some(*f)).map(Target::Navigate) } diff --git a/crates/ui-egui/src/proto_variant_connect_tests.rs b/crates/ui-egui/src/proto_variant_connect_tests.rs index b9f6ba812..db5f55a9d 100644 --- a/crates/ui-egui/src/proto_variant_connect_tests.rs +++ b/crates/ui-egui/src/proto_variant_connect_tests.rs @@ -28,6 +28,11 @@ struct Setup { } fn setup() -> Setup { + setup_in(false) +} + +/// `grouped`: the set is put in a group, inside a section around everything. +fn setup_in(grouped: bool) -> Setup { let mut s = Session::new(); let mut variant = |name: &str, x: f64| { let f = id(&s.execute("frame.create", &json!({"x": x, "y": 0, "width": 100, "height": 80, "name": name})).unwrap()); @@ -38,6 +43,12 @@ fn setup() -> Setup { let layer = id(&s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 30, "height": 20, "parent": default})).unwrap()); let outside = id(&s.execute("frame.create", &json!({"x": 0, "y": 500, "width": 200, "height": 150, "name": "Outside"})).unwrap()); let set = id(&s.execute("component.combineVariants", &json!({"ids": [default, hover]})).unwrap()); + if grouped { + let group = id(&s.execute("object.group", &json!({"ids": [set]})).unwrap()); + let section = id(&s.execute("node.create", &json!({"type": "section", "x": -200, "y": -200, "width": 1000, "height": 1000})).unwrap()); + s.execute("node.reparent", &json!({"ids": [group], "parent": section})).unwrap(); + assert_eq!(s.doc().unwrap().top_level_frame(default), None, "a set in a group has no top-level frame"); + } let mut u = Ui::new(s); u.app.ui.right_tab = RightTab::Prototype; Setup { u, set, default, hover, layer, outside } @@ -114,6 +125,21 @@ fn dropped_on_the_sets_background_or_its_own_variant_it_adds_nothing() { let _ = t.set; } +/// A set in a group in a section (CodeRabbit, #2161): its background still gives nothing, not a +/// Navigate to the section, and a sibling still gives Change to. +#[test] +fn in_a_grouped_set_the_background_adds_nothing_and_a_sibling_changes_to() { + let mut t = setup_in(true); + let (a, b) = (screen_centre(&t.u.app, t.default), screen_centre(&t.u.app, t.hover)); + let gap = pos2((a.x + b.x) / 2.0, a.y); + let src = t.default; + drag(&mut t, src, gap); + assert!(interactions(&t, t.default).is_empty(), "{:?}", interactions(&t, t.default)); + let to = screen_centre(&t.u.app, t.hover); + drag(&mut t, src, to); + assert_change_to(&t, t.default, t.hover); +} + #[test] fn a_variant_dropped_on_a_frame_outside_the_set_still_navigates() { let mut t = setup();