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:
parent
d3ec1f29f8
commit
2093046942
3 changed files with 77 additions and 89 deletions
|
|
@ -6,6 +6,7 @@ use gpui::{
|
|||
use gpui_component::{
|
||||
ContextModal,
|
||||
clipboard::Clipboard,
|
||||
h_flex,
|
||||
input::{Input, InputState},
|
||||
label::Label,
|
||||
v_flex,
|
||||
|
|
@ -60,17 +61,24 @@ impl Render for ClipboardStory {
|
|||
.gap_6()
|
||||
.child(
|
||||
section("Clipboard").max_w_md().child(
|
||||
Clipboard::new("clipboard1")
|
||||
.content(|_, _| Label::new("A clipboard button"))
|
||||
.value_fn({
|
||||
let view = cx.entity().clone();
|
||||
move |_, cx| {
|
||||
SharedString::from(format!("masked :{}", view.read(cx).masked))
|
||||
}
|
||||
})
|
||||
.on_copied(|value, window, cx| {
|
||||
window.push_notification(format!("Copied value: {}", value), cx)
|
||||
}),
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Label::new("A clipboard button"))
|
||||
.child(
|
||||
Clipboard::new("clipboard1")
|
||||
.value_fn({
|
||||
let view = cx.entity().clone();
|
||||
move |_, cx| {
|
||||
SharedString::from(format!(
|
||||
"masked :{}",
|
||||
view.read(cx).masked
|
||||
))
|
||||
}
|
||||
})
|
||||
.on_copied(|value, window, cx| {
|
||||
window.push_notification(format!("Copied value: {}", value), cx)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
|
|
|
|||
|
|
@ -2,33 +2,34 @@ use std::{cell::Cell, rc::Rc, time::Duration};
|
|||
|
||||
use gpui::{
|
||||
prelude::FluentBuilder, AnyElement, App, ClipboardItem, Element, ElementId, GlobalElementId,
|
||||
IntoElement, LayoutId, ParentElement, SharedString, Styled, Window,
|
||||
IntoElement, LayoutId, SharedString, Window,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
button::{Button, ButtonVariants as _},
|
||||
h_flex, IconName, Sizable as _,
|
||||
IconName, Sizable as _,
|
||||
};
|
||||
|
||||
/// An element that provides clipboard copy functionality.
|
||||
pub struct Clipboard {
|
||||
id: ElementId,
|
||||
value: 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)>>,
|
||||
}
|
||||
|
||||
impl Clipboard {
|
||||
/// Create a new Clipboard element with the given ID.
|
||||
pub fn new(id: impl Into<ElementId>) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
value: SharedString::default(),
|
||||
value_fn: None,
|
||||
content_builder: 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 {
|
||||
self.value = value.into();
|
||||
self
|
||||
|
|
@ -45,6 +46,7 @@ impl Clipboard {
|
|||
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
|
||||
where
|
||||
F: Fn(SharedString, &mut Window, &mut App) + 'static,
|
||||
|
|
@ -52,17 +54,6 @@ impl Clipboard {
|
|||
self.copied_callback = Some(Rc::new(handler));
|
||||
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 {
|
||||
|
|
@ -73,6 +64,7 @@ impl IntoElement for Clipboard {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Default)]
|
||||
pub struct ClipboardState {
|
||||
copied: Cell<bool>,
|
||||
|
|
@ -101,10 +93,6 @@ impl Element for Clipboard {
|
|||
window.with_element_state::<ClipboardState, _>(global_id.unwrap(), |state, window| {
|
||||
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 clipboard_id = self.id.clone();
|
||||
let copied_callback = self.copied_callback.as_ref().map(|c| c.clone());
|
||||
|
|
@ -112,43 +100,37 @@ impl Element for Clipboard {
|
|||
let copide_value = copied.get();
|
||||
let value_fn = self.value_fn.clone();
|
||||
|
||||
let mut element = h_flex()
|
||||
.gap_1()
|
||||
.items_center()
|
||||
.when_some(content_element, |this, element| this.child(element))
|
||||
.child(
|
||||
Button::new(clipboard_id)
|
||||
.icon(if copide_value {
|
||||
IconName::Check
|
||||
} else {
|
||||
IconName::Copy
|
||||
let mut element = Button::new(clipboard_id)
|
||||
.icon(if copide_value {
|
||||
IconName::Check
|
||||
} else {
|
||||
IconName::Copy
|
||||
})
|
||||
.ghost()
|
||||
.xsmall()
|
||||
.when(!copide_value, |this| {
|
||||
this.on_click(move |_, window, cx| {
|
||||
cx.stop_propagation();
|
||||
let value = value_fn
|
||||
.as_ref()
|
||||
.map(|f| f(window, cx))
|
||||
.unwrap_or_else(|| value.clone());
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(value.to_string()));
|
||||
copied.set(true);
|
||||
|
||||
let copied = copied.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
cx.background_executor().timer(Duration::from_secs(2)).await;
|
||||
|
||||
copied.set(false);
|
||||
})
|
||||
.ghost()
|
||||
.xsmall()
|
||||
.when(!copide_value, |this| {
|
||||
this.on_click(move |_, window, cx| {
|
||||
cx.stop_propagation();
|
||||
let value = value_fn
|
||||
.as_ref()
|
||||
.map(|f| f(window, cx))
|
||||
.unwrap_or_else(|| value.clone());
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(value.to_string()));
|
||||
copied.set(true);
|
||||
.detach();
|
||||
|
||||
let copied = copied.clone();
|
||||
cx.spawn(async move |cx| {
|
||||
cx.background_executor().timer(Duration::from_secs(2)).await;
|
||||
|
||||
copied.set(false);
|
||||
})
|
||||
.detach();
|
||||
|
||||
if let Some(callback) = &copied_callback {
|
||||
callback(value.clone(), window, cx);
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
if let Some(callback) = &copied_callback {
|
||||
callback(value.clone(), window, cx);
|
||||
}
|
||||
})
|
||||
})
|
||||
.into_any_element();
|
||||
|
||||
((element.request_layout(window, cx), element), state)
|
||||
|
|
|
|||
|
|
@ -25,17 +25,12 @@ Clipboard::new("my-clipboard")
|
|||
})
|
||||
```
|
||||
|
||||
### With Dynamic Content
|
||||
### Using Dynamic Values
|
||||
|
||||
```rust
|
||||
Clipboard::new("clipboard")
|
||||
.content(|_, _| Label::new("Copy this text"))
|
||||
.value("Hello, World!")
|
||||
```
|
||||
The `value_fn` method allows you to provide a closure that generates the content to be copied at the time of the copy action.
|
||||
|
||||
### Using Value Function
|
||||
|
||||
For dynamic values that should be computed when the copy action occurs:
|
||||
- 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.
|
||||
|
||||
```rust
|
||||
let state = some_state.clone();
|
||||
|
|
@ -53,14 +48,14 @@ Clipboard::new("dynamic-clipboard")
|
|||
```rust
|
||||
use gpui_component::label::Label;
|
||||
|
||||
Clipboard::new("custom-clipboard")
|
||||
.content(|_, _|
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Label::new("Share URL"))
|
||||
.child(Icon::new(IconName::Share))
|
||||
)
|
||||
.value("https://example.com")
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Label::new("Share URL"))
|
||||
.child(Icon::new(IconName::Share))
|
||||
.child(
|
||||
Clipboard::new("custom-clipboard")
|
||||
.value("https://example.com")
|
||||
)
|
||||
```
|
||||
|
||||
### In Input Fields
|
||||
|
|
@ -101,12 +96,16 @@ Clipboard::new("simple")
|
|||
### With User Feedback
|
||||
|
||||
```rust
|
||||
Clipboard::new("feedback")
|
||||
.content(|_, _| Label::new("API Key"))
|
||||
.value("sk-1234567890abcdef")
|
||||
.on_copied(|_, window, cx| {
|
||||
window.push_notification("API key copied to clipboard", cx)
|
||||
})
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(Label::new("Your API Key:"))
|
||||
.child(
|
||||
Clipboard::new("feedback")
|
||||
.value("sk-1234567890abcdef")
|
||||
.on_copied(|_, window, cx| {
|
||||
window.push_notification("API key copied to clipboard", cx)
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
### Form Field Integration
|
||||
|
|
@ -149,7 +148,6 @@ let app_state = cx.new(|_| AppState {
|
|||
});
|
||||
|
||||
Clipboard::new("current-url")
|
||||
.content(|_, _| Label::new("Share current page"))
|
||||
.value_fn({
|
||||
let state = app_state.clone();
|
||||
move |_, cx| {
|
||||
|
|
|
|||
Loading…
Reference in a new issue