clipboard: Removed content method from Clipboard. (#1520)

## Break Change

- The `content` method has been removed from `Clipboard`, if you want
display something, you can wrap it in a h_flex.
This commit is contained in:
Jason Lee 2025-11-05 15:17:58 +08:00 committed by GitHub
parent d3ec1f29f8
commit 2093046942
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 89 deletions

View file

@ -6,6 +6,7 @@ use gpui::{
use gpui_component::{ use gpui_component::{
ContextModal, ContextModal,
clipboard::Clipboard, clipboard::Clipboard,
h_flex,
input::{Input, InputState}, input::{Input, InputState},
label::Label, label::Label,
v_flex, v_flex,
@ -60,18 +61,25 @@ impl Render for ClipboardStory {
.gap_6() .gap_6()
.child( .child(
section("Clipboard").max_w_md().child( section("Clipboard").max_w_md().child(
h_flex()
.gap_2()
.child(Label::new("A clipboard button"))
.child(
Clipboard::new("clipboard1") Clipboard::new("clipboard1")
.content(|_, _| Label::new("A clipboard button"))
.value_fn({ .value_fn({
let view = cx.entity().clone(); let view = cx.entity().clone();
move |_, cx| { move |_, cx| {
SharedString::from(format!("masked :{}", view.read(cx).masked)) SharedString::from(format!(
"masked :{}",
view.read(cx).masked
))
} }
}) })
.on_copied(|value, window, cx| { .on_copied(|value, window, cx| {
window.push_notification(format!("Copied value: {}", value), cx) window.push_notification(format!("Copied value: {}", value), cx)
}), }),
), ),
),
) )
.child( .child(
section("With in an Input").max_w_md().child( section("With in an Input").max_w_md().child(

View file

@ -2,33 +2,34 @@ use std::{cell::Cell, rc::Rc, time::Duration};
use gpui::{ use gpui::{
prelude::FluentBuilder, AnyElement, App, ClipboardItem, Element, ElementId, GlobalElementId, prelude::FluentBuilder, AnyElement, App, ClipboardItem, Element, ElementId, GlobalElementId,
IntoElement, LayoutId, ParentElement, SharedString, Styled, Window, IntoElement, LayoutId, SharedString, Window,
}; };
use crate::{ use crate::{
button::{Button, ButtonVariants as _}, button::{Button, ButtonVariants as _},
h_flex, IconName, Sizable as _, IconName, Sizable as _,
}; };
/// An element that provides clipboard copy functionality.
pub struct Clipboard { pub struct Clipboard {
id: ElementId, id: ElementId,
value: SharedString, value: SharedString,
value_fn: Option<Rc<dyn Fn(&mut Window, &mut App) -> SharedString>>, value_fn: Option<Rc<dyn Fn(&mut Window, &mut App) -> SharedString>>,
content_builder: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyElement>>,
copied_callback: Option<Rc<dyn Fn(SharedString, &mut Window, &mut App)>>, copied_callback: Option<Rc<dyn Fn(SharedString, &mut Window, &mut App)>>,
} }
impl Clipboard { impl Clipboard {
/// Create a new Clipboard element with the given ID.
pub fn new(id: impl Into<ElementId>) -> Self { pub fn new(id: impl Into<ElementId>) -> Self {
Self { Self {
id: id.into(), id: id.into(),
value: SharedString::default(), value: SharedString::default(),
value_fn: None, value_fn: None,
content_builder: None,
copied_callback: None, copied_callback: None,
} }
} }
/// Set the value for copying to the clipboard. Default is an empty string.
pub fn value(mut self, value: impl Into<SharedString>) -> Self { pub fn value(mut self, value: impl Into<SharedString>) -> Self {
self.value = value.into(); self.value = value.into();
self self
@ -45,6 +46,7 @@ impl Clipboard {
self self
} }
/// Set a callback to be invoked when the content is copied to the clipboard.
pub fn on_copied<F>(mut self, handler: F) -> Self pub fn on_copied<F>(mut self, handler: F) -> Self
where where
F: Fn(SharedString, &mut Window, &mut App) + 'static, F: Fn(SharedString, &mut Window, &mut App) + 'static,
@ -52,17 +54,6 @@ impl Clipboard {
self.copied_callback = Some(Rc::new(handler)); self.copied_callback = Some(Rc::new(handler));
self self
} }
pub fn content<E, F>(mut self, builder: F) -> Self
where
E: IntoElement,
F: Fn(&mut Window, &mut App) -> E + 'static,
{
self.content_builder = Some(Box::new(move |window, cx| {
builder(window, cx).into_any_element()
}));
self
}
} }
impl IntoElement for Clipboard { impl IntoElement for Clipboard {
@ -73,6 +64,7 @@ impl IntoElement for Clipboard {
} }
} }
#[doc(hidden)]
#[derive(Default)] #[derive(Default)]
pub struct ClipboardState { pub struct ClipboardState {
copied: Cell<bool>, copied: Cell<bool>,
@ -101,10 +93,6 @@ impl Element for Clipboard {
window.with_element_state::<ClipboardState, _>(global_id.unwrap(), |state, window| { window.with_element_state::<ClipboardState, _>(global_id.unwrap(), |state, window| {
let state = state.unwrap_or_default(); let state = state.unwrap_or_default();
let content_element = self
.content_builder
.as_ref()
.map(|builder| builder(window, cx).into_any_element());
let value = self.value.clone(); let value = self.value.clone();
let clipboard_id = self.id.clone(); let clipboard_id = self.id.clone();
let copied_callback = self.copied_callback.as_ref().map(|c| c.clone()); let copied_callback = self.copied_callback.as_ref().map(|c| c.clone());
@ -112,12 +100,7 @@ impl Element for Clipboard {
let copide_value = copied.get(); let copide_value = copied.get();
let value_fn = self.value_fn.clone(); let value_fn = self.value_fn.clone();
let mut element = h_flex() let mut element = Button::new(clipboard_id)
.gap_1()
.items_center()
.when_some(content_element, |this, element| this.child(element))
.child(
Button::new(clipboard_id)
.icon(if copide_value { .icon(if copide_value {
IconName::Check IconName::Check
} else { } else {
@ -147,8 +130,7 @@ impl Element for Clipboard {
callback(value.clone(), window, cx); callback(value.clone(), window, cx);
} }
}) })
}), })
)
.into_any_element(); .into_any_element();
((element.request_layout(window, cx), element), state) ((element.request_layout(window, cx), element), state)

View file

@ -25,17 +25,12 @@ Clipboard::new("my-clipboard")
}) })
``` ```
### With Dynamic Content ### Using Dynamic Values
```rust The `value_fn` method allows you to provide a closure that generates the content to be copied at the time of the copy action.
Clipboard::new("clipboard")
.content(|_, _| Label::new("Copy this text"))
.value("Hello, World!")
```
### Using Value Function - This is useful when the content to be copied depends on the current state of the application.
- And in some cases, it may have a larger overhead to compute, so you only want to do it when the user actually clicks the copy button.
For dynamic values that should be computed when the copy action occurs:
```rust ```rust
let state = some_state.clone(); let state = some_state.clone();
@ -53,14 +48,14 @@ Clipboard::new("dynamic-clipboard")
```rust ```rust
use gpui_component::label::Label; use gpui_component::label::Label;
Clipboard::new("custom-clipboard")
.content(|_, _|
h_flex() h_flex()
.gap_2() .gap_2()
.child(Label::new("Share URL")) .child(Label::new("Share URL"))
.child(Icon::new(IconName::Share)) .child(Icon::new(IconName::Share))
) .child(
Clipboard::new("custom-clipboard")
.value("https://example.com") .value("https://example.com")
)
``` ```
### In Input Fields ### In Input Fields
@ -101,12 +96,16 @@ Clipboard::new("simple")
### With User Feedback ### With User Feedback
```rust ```rust
h_flex()
.gap_2()
.child(Label::new("Your API Key:"))
.child(
Clipboard::new("feedback") Clipboard::new("feedback")
.content(|_, _| Label::new("API Key"))
.value("sk-1234567890abcdef") .value("sk-1234567890abcdef")
.on_copied(|_, window, cx| { .on_copied(|_, window, cx| {
window.push_notification("API key copied to clipboard", cx) window.push_notification("API key copied to clipboard", cx)
}) })
)
``` ```
### Form Field Integration ### Form Field Integration
@ -149,7 +148,6 @@ let app_state = cx.new(|_| AppState {
}); });
Clipboard::new("current-url") Clipboard::new("current-url")
.content(|_, _| Label::new("Share current page"))
.value_fn({ .value_fn({
let state = app_state.clone(); let state = app_state.clone();
move |_, cx| { move |_, cx| {