mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 09:09:21 -05:00
159 lines
4.8 KiB
Rust
159 lines
4.8 KiB
Rust
use crate::{js, js_fut, use_event_listener, use_supported, UseTimeoutFnReturn};
|
|
use default_struct_builder::DefaultBuilder;
|
|
use leptos::ev::{copy, cut};
|
|
use leptos::*;
|
|
|
|
/// Reactive [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API).
|
|
/// Provides the ability to respond to clipboard commands (cut, copy, and paste)
|
|
/// as well as to asynchronously read from and write to the system clipboard.
|
|
/// Access to the contents of the clipboard is gated behind the
|
|
/// [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API).
|
|
/// Without user permission, reading or altering the clipboard contents is not permitted.
|
|
///
|
|
/// ## Demo
|
|
///
|
|
/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_clipboard)
|
|
///
|
|
/// ## Usage
|
|
///
|
|
/// ```
|
|
/// # use leptos::*;
|
|
/// # use leptos_use::{use_clipboard, UseClipboardReturn};
|
|
/// #
|
|
/// # #[component]
|
|
/// # fn Demo() -> impl IntoView {
|
|
/// let UseClipboardReturn { is_supported, text, copied, copy } = use_clipboard();
|
|
///
|
|
/// view! {
|
|
/// <Show
|
|
/// when=move || is_supported.get()
|
|
/// fallback=move || view! { <p>Your browser does not support Clipboard API</p> }
|
|
/// >
|
|
/// <button on:click={
|
|
/// let copy = copy.clone();
|
|
/// move |_| copy("Hello!")
|
|
/// }>
|
|
/// <Show when=move || copied.get() fallback=move || "Copy">
|
|
/// "Copied!"
|
|
/// </Show>
|
|
/// </button>
|
|
/// </Show>
|
|
/// }
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// ## Server-Side Rendering
|
|
///
|
|
/// On the server the returnd `text` signal will always be `None` and `copy` is a no-op.
|
|
pub fn use_clipboard() -> UseClipboardReturn<impl Fn(&str) + Clone> {
|
|
use_clipboard_with_options(UseClipboardOptions::default())
|
|
}
|
|
|
|
/// Version of [`use_clipboard`] that takes a `UseClipboardOptions`. See [`use_clipboard`] for how to use.
|
|
pub fn use_clipboard_with_options(
|
|
options: UseClipboardOptions,
|
|
) -> UseClipboardReturn<impl Fn(&str) + Clone> {
|
|
let UseClipboardOptions {
|
|
copied_reset_delay,
|
|
read,
|
|
} = options;
|
|
|
|
let is_supported = use_supported(|| {
|
|
js!("clipboard" in &window()
|
|
.navigator())
|
|
});
|
|
|
|
let (text, set_text) = create_signal(None);
|
|
let (copied, set_copied) = create_signal(false);
|
|
|
|
let UseTimeoutFnReturn { start, .. } = crate::use_timeout_fn::use_timeout_fn(
|
|
move |_: ()| {
|
|
set_copied.set(false);
|
|
},
|
|
copied_reset_delay,
|
|
);
|
|
|
|
let update_text = move |_| {
|
|
if is_supported.get() {
|
|
spawn_local(async move {
|
|
let clipboard = window().navigator().clipboard();
|
|
if let Ok(text) = js_fut!(clipboard.read_text()).await {
|
|
set_text.set(text.as_string());
|
|
}
|
|
})
|
|
}
|
|
};
|
|
|
|
if is_supported.get() && read {
|
|
let _ = use_event_listener(window(), copy, update_text);
|
|
let _ = use_event_listener(window(), cut, update_text);
|
|
}
|
|
|
|
let do_copy = {
|
|
let start = start.clone();
|
|
|
|
move |value: &str| {
|
|
if is_supported.get() {
|
|
let start = start.clone();
|
|
let value = value.to_owned();
|
|
|
|
spawn_local(async move {
|
|
let clipboard = window().navigator().clipboard();
|
|
if js_fut!(clipboard.write_text(&value)).await.is_ok() {
|
|
set_text.set(Some(value));
|
|
set_copied.set(true);
|
|
start(());
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
UseClipboardReturn {
|
|
is_supported,
|
|
text: text.into(),
|
|
copied: copied.into(),
|
|
copy: do_copy,
|
|
}
|
|
}
|
|
|
|
/// Options for [`use_clipboard_with_options`].
|
|
#[derive(DefaultBuilder)]
|
|
pub struct UseClipboardOptions {
|
|
/// When `true` event handlers are added so that the returned signal `text` is updated whenever the clipboard changes.
|
|
/// Defaults to `false`.
|
|
///
|
|
/// > Please note that clipboard changes are only detected when copying or cutting text inside the same document.
|
|
read: bool,
|
|
|
|
/// After how many milliseconds after copying should the returned signal `copied` be set to `false`?
|
|
/// Defaults to 1500.
|
|
copied_reset_delay: f64,
|
|
}
|
|
|
|
impl Default for UseClipboardOptions {
|
|
fn default() -> Self {
|
|
Self {
|
|
read: false,
|
|
copied_reset_delay: 1500.0,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Return type of [`use_clipboard`].
|
|
pub struct UseClipboardReturn<CopyFn>
|
|
where
|
|
CopyFn: Fn(&str) + Clone,
|
|
{
|
|
/// Whether the Clipboard API is supported.
|
|
pub is_supported: Signal<bool>,
|
|
|
|
/// The current state of the clipboard.
|
|
pub text: Signal<Option<String>>,
|
|
|
|
/// `true` for [`UseClipboardOptions::copied_reset_delay`] milliseconds after copying.
|
|
pub copied: Signal<bool>,
|
|
|
|
/// Copy the given text to the clipboard.
|
|
pub copy: CopyFn,
|
|
}
|