From 208160652b1dedd543bf2c9de8f8d757b4ca902b Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 6 Jul 2026 16:14:33 +0800 Subject: [PATCH] popover: Clarify what the anchor means in docs and API comments Users read the `anchor` option as "which side of the trigger the popover shows on" and reported it as inverted (#2534). It actually uses GPUI's corner-anchoring model. Explain it with a concrete image instead: the anchor is where the popover's pointer tip (like a speech bubble's tail) sits relative to the trigger, and the popover hangs off that point. Applied to the `anchor()` comments on `Popover`/`HoverCard` and their docs (en + zh-CN), added a small `TopLeft` example diagram, and dropped stale wording that implied two separate `Anchor` types. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/story/src/stories/popover_story.rs | 12 ++++---- crates/ui/src/hover_card.rs | 4 +++ crates/ui/src/popover.rs | 8 +++-- docs/docs/components/hover-card.md | 11 +++++++ docs/docs/components/popover.md | 37 +++++++++++------------ docs/zh-CN/docs/components/hover-card.md | 11 +++++++ docs/zh-CN/docs/components/popover.md | 19 +++++++----- 7 files changed, 65 insertions(+), 37 deletions(-) diff --git a/crates/story/src/stories/popover_story.rs b/crates/story/src/stories/popover_story.rs index afedb778b4..3a62f64e7a 100644 --- a/crates/story/src/stories/popover_story.rs +++ b/crates/story/src/stories/popover_story.rs @@ -353,20 +353,20 @@ impl Render for PopoverStory { .max_w(px(600.)) .anchor(Anchor::TopLeft) .trigger(Button::new("btn").outline().label("TopLeft")) - .child("This is a Popover on the Top Left."), + .child("Anchored to the trigger's top-left."), ) .child( Popover::new("anchor-top-center") .max_w(px(600.)) .anchor(Anchor::TopCenter) .trigger(Button::new("btn").outline().label("TopCenter")) - .child("This is a Popover on the Top Center."), + .child("Anchored to the trigger's top-center."), ) .child( Popover::new("anchor-top-right") .anchor(Anchor::TopRight) .trigger(Button::new("btn").outline().label("TopRight")) - .child("This is a Popover on the Top Right."), + .child("Anchored to the trigger's top-right."), ), ), ) @@ -379,19 +379,19 @@ impl Render for PopoverStory { Popover::new("anchor-bottom-left") .trigger(Button::new("btn").outline().label("BottomLeft")) .anchor(Anchor::BottomLeft) - .child("This is a Popover on the Bottom Left."), + .child("Anchored to the trigger's bottom-left."), ) .child( Popover::new("anchor-bottom-center") .trigger(Button::new("btn").outline().label("BottomCenter")) .anchor(Anchor::BottomCenter) - .child("This is a Popover on the Bottom Center."), + .child("Anchored to the trigger's bottom-center."), ) .child( Popover::new("anchor-bottom-right") .anchor(Anchor::BottomRight) .trigger(Button::new("btn").outline().label("BottomRight")) - .child("This is a Popover on the Bottom Right."), + .child("Anchored to the trigger's bottom-right."), ), ), ), diff --git a/crates/ui/src/hover_card.rs b/crates/ui/src/hover_card.rs index 69ef839bc2..3067b2ed29 100644 --- a/crates/ui/src/hover_card.rs +++ b/crates/ui/src/hover_card.rs @@ -49,6 +49,10 @@ impl HoverCard { } /// Set the anchor corner of the hover card, default is [`Anchor::TopCenter`]. + /// + /// Imagine the card has a pointer tip (like a speech bubble's tail). The anchor + /// is where that tip sits relative to the trigger — e.g. `Anchor::TopCenter` + /// places it at the trigger's top center. The card then hangs off that point. pub fn anchor(mut self, anchor: impl Into) -> Self { self.anchor = anchor.into(); self diff --git a/crates/ui/src/popover.rs b/crates/ui/src/popover.rs index 6d4201a5b2..108753580d 100644 --- a/crates/ui/src/popover.rs +++ b/crates/ui/src/popover.rs @@ -62,10 +62,12 @@ impl Popover { } } - /// Set the anchor corner of the popover, default is `Anchor::TopLeft`. + /// Set the anchor corner of the popover, default is [`Anchor::TopLeft`]. /// - /// This method is kept for backward compatibility with `Anchor` type. - /// Internally, it converts `Anchor` to `Anchor`. + /// Imagine the popover has a pointer tip (like a speech bubble's tail). The + /// anchor is where that tip sits relative to the trigger: `Anchor::TopLeft` + /// places it at the trigger's top-left corner, `Anchor::BottomRight` at the + /// bottom-right, and so on. The popover then hangs off that point. pub fn anchor(mut self, anchor: impl Into) -> Self { self.anchor = anchor.into(); self diff --git a/docs/docs/components/hover-card.md b/docs/docs/components/hover-card.md index cbc3d28370..f7c2ae4e1f 100644 --- a/docs/docs/components/hover-card.md +++ b/docs/docs/components/hover-card.md @@ -141,6 +141,17 @@ HoverCard supports 6 positioning options using the [Anchor] type: - BottomCenter - BottomRight +Imagine the card has a pointer tip (like a speech bubble's tail). The anchor is where that tip sits relative to the trigger — `TopCenter` places it at the trigger's top center, `BottomRight` at the bottom-right, and so on. The card then hangs off that point. + +For example, `Anchor::TopLeft` places the card just below the trigger, left-aligned to it: + +```text +[ Trigger ] +┌──────────────┐ +│ Hover Card │ +└──────────────┘ +``` + ### Custom Content Builder For performance optimization, you can provide a content builder function for more complex case, which only calls when the HoverCard is opened: diff --git a/docs/docs/components/popover.md b/docs/docs/components/popover.md index fdb899507a..6f20fde1ba 100644 --- a/docs/docs/components/popover.md +++ b/docs/docs/components/popover.md @@ -35,57 +35,53 @@ Popover::new("basic-popover") ### Popover with Custom Positioning -The `anchor` method allows you to specify where the popover appears relative to the trigger element. It accepts both `Anchor` and `Anchor` types. +The `anchor` method controls how the popover attaches to the trigger, using the [`Anchor`] type. -**Using `Anchor` type** (4 corner positions): +Imagine the popover has a pointer tip (like a speech bubble's tail). The anchor is where that tip sits relative to the trigger — `Anchor::TopLeft` places it at the trigger's top-left corner, `Anchor::BottomRight` at the bottom-right, and so on. The popover then hangs off that point. -```rust -use gpui::Anchor; +For example, `Anchor::TopLeft` places the popover just below the trigger, left-aligned to it: -Popover::new("positioned-popover") - .anchor(Anchor::TopRight) - .trigger(Button::new("top-right").label("Top Right").outline()) - .child("This popover appears at the top right") +```text +[ Trigger ] +┌──────────────┐ +│ Popover │ +└──────────────┘ ``` -**Using `Anchor` type** (6 positions including center): - -The `Anchor` type provides more positioning options, including center positions: - ```rust use gpui_component::Anchor; -// Top positions +// Anchored to the trigger's top corners Popover::new("top-left") .anchor(Anchor::TopLeft) .trigger(Button::new("btn").label("Top Left").outline()) - .child("Anchored to top left") + .child("Anchored to the trigger's top-left") Popover::new("top-center") .anchor(Anchor::TopCenter) .trigger(Button::new("btn").label("Top Center").outline()) - .child("Anchored to top center") + .child("Anchored to the trigger's top-center") Popover::new("top-right") .anchor(Anchor::TopRight) .trigger(Button::new("btn").label("Top Right").outline()) - .child("Anchored to top right") + .child("Anchored to the trigger's top-right") -// Bottom positions +// Anchored to the trigger's bottom corners Popover::new("bottom-left") .anchor(Anchor::BottomLeft) .trigger(Button::new("btn").label("Bottom Left").outline()) - .child("Anchored to bottom left") + .child("Anchored to the trigger's bottom-left") Popover::new("bottom-center") .anchor(Anchor::BottomCenter) .trigger(Button::new("btn").label("Bottom Center").outline()) - .child("Anchored to bottom center") + .child("Anchored to the trigger's bottom-center") Popover::new("bottom-right") .anchor(Anchor::BottomRight) .trigger(Button::new("btn").label("Bottom Right").outline()) - .child("Anchored to bottom right") + .child("Anchored to the trigger's bottom-right") ``` ### View in Popover @@ -241,3 +237,4 @@ Popover::new("default-open-popover") [Render]: https://docs.rs/gpui/latest/gpui/trait.Render.html [RenderOnce]: https://docs.rs/gpui/latest/gpui/trait.RenderOnce.html [Styled]: https://docs.rs/gpui/latest/gpui/trait.Styled.html +[`Anchor`]: https://docs.rs/gpui-component/latest/gpui_component/enum.Anchor.html diff --git a/docs/zh-CN/docs/components/hover-card.md b/docs/zh-CN/docs/components/hover-card.md index c32fde98c9..1573b609a0 100644 --- a/docs/zh-CN/docs/components/hover-card.md +++ b/docs/zh-CN/docs/components/hover-card.md @@ -141,6 +141,17 @@ HoverCard 支持通过 [Anchor] 设置 6 种定位: - BottomCenter - BottomRight +可以把卡片想象成有一个箭头尖角(像对话气泡的小三角)。anchor 指的就是这个尖角相对于触发器落在哪个点——`TopCenter` 把它放在触发器的顶部中间,`BottomRight` 放在右下角,以此类推。卡片就从这个点挂出来。 + +例如 `Anchor::TopLeft` 会让卡片出现在触发器正下方,并与其左对齐: + +```text +[ Trigger ] +┌──────────────┐ +│ Hover Card │ +└──────────────┘ +``` + ### 使用动态内容构建器 对于较复杂的内容,可以使用 `content` builder,在 HoverCard 打开时再生成内容: diff --git a/docs/zh-CN/docs/components/popover.md b/docs/zh-CN/docs/components/popover.md index c0412fa879..cb90b7f520 100644 --- a/docs/zh-CN/docs/components/popover.md +++ b/docs/zh-CN/docs/components/popover.md @@ -35,15 +35,17 @@ Popover::new("basic-popover") ### 自定义定位 -`anchor` 方法用于指定 Popover 相对于触发器的位置,支持 `Anchor` 和 `Anchor` 两种类型。 +`anchor` 方法用于控制 Popover 如何贴合触发器,使用 [`Anchor`] 类型。 -```rust -use gpui::Anchor; +可以把 Popover 想象成有一个箭头尖角(像对话气泡的小三角)。anchor 指的就是这个尖角相对于触发器落在哪个点——`Anchor::TopLeft` 把它放在触发器的左上角,`Anchor::BottomRight` 放在右下角,以此类推。Popover 就从这个点挂出来。 + +例如 `Anchor::TopLeft` 会让 Popover 出现在触发器正下方,并与其左对齐: -Popover::new("positioned-popover") - .anchor(Anchor::TopRight) - .trigger(Button::new("top-right").label("Top Right").outline()) - .child("This popover appears at the top right") +```text +[ Trigger ] +┌──────────────┐ +│ Popover │ +└──────────────┘ ``` ```rust @@ -52,7 +54,7 @@ use gpui_component::Anchor; Popover::new("top-center") .anchor(Anchor::TopCenter) .trigger(Button::new("btn").label("Top Center").outline()) - .child("Anchored to top center") + .child("Anchored to the trigger's top-center") ``` ### 在 Popover 中渲染 View @@ -187,3 +189,4 @@ Popover::new("default-open-popover") [Render]: https://docs.rs/gpui/latest/gpui/trait.Render.html [RenderOnce]: https://docs.rs/gpui/latest/gpui/trait.RenderOnce.html [Styled]: https://docs.rs/gpui/latest/gpui/trait.Styled.html +[`Anchor`]: https://docs.rs/gpui-component/latest/gpui_component/enum.Anchor.html