@crosscopy/clipboard 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Cargo.toml CHANGED
@@ -21,3 +21,4 @@ napi-build = "2.0.1"
21
21
  [profile.release]
22
22
  lto = true
23
23
  strip = "symbols"
24
+
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # Clipboard
2
+
3
+ npm package: https://www.npmjs.com/package/@crosscopy/clipboard
4
+ GitHub: https://github.com/crosscopy/clipboard
5
+
6
+ > This is a clipboard API npm package that allows you to copy and paste data to and from the clipboard.
7
+ > There doesn't seem to be a good clipboard package for node.js (that supports data format beyond text), so I decided to make one.
8
+ > Data Format Supported
9
+ >
10
+ > - Text
11
+ > - Image
12
+ > - Rich Text Format
13
+ > - Files
14
+ > - HTML
15
+
16
+ ## Acknowledgements
17
+
18
+ - [ChurchTao/clipboard-rs](https://github.com/ChurchTao/clipboard-rs) is written in rust, which is used to provide the native clipboard support for this package across Linux, Windows and MacOS. This package is basically a wrapper around this rust package.
19
+ - https://crates.io/crates/clipboard-rs
20
+ - [napi.rs](https://napi.rs/) was used to create the node.js addon for this package, so that API calls written in rust can be called from node.js.
21
+
22
+ ## API
23
+
24
+ Detailed API function declarations can be found in the [index.d.ts](./index.d.ts).
25
+
26
+ Or you can refer to the source code in [src/lib.rs](./src/lib.rs).
27
+
28
+ ## Sample
29
+
30
+ ```javascript
31
+ import Clipboard from "@crosscopy/clipboard";
32
+
33
+ console.log(await Clipboard.getText());
34
+
35
+ console.log(await Clipboard.getHtml());
36
+
37
+ if (await Clipboard.hasImage()) {
38
+ console.log(await Clipboard.getImageBase64());
39
+ } else {
40
+ console.log("No Image");
41
+ }
42
+ ```
43
+
44
+ ## Plan
45
+
46
+ A clipboard listener will be added soon for monitoring clipboard changes and get notified when the clipboard content changes.
package/exp.ts CHANGED
@@ -1,16 +1,12 @@
1
- import { getText, getImageBase64, Animal, asyncGetText } from "./index.js";
2
1
  import Clipboard from "./index.js";
3
2
 
4
- // const text = getText();
3
+ console.log(await Clipboard.getText());
5
4
 
6
- // console.log(text);
5
+ console.log(await Clipboard.getHtml());
7
6
 
8
- // const dog = new Animal("dog", 5);
9
- // console.log(dog.name);
10
- // dog.changeName("dog 2");
11
- // console.log(dog.name);
12
7
 
13
- // console.log(Animal.getText());
14
-
15
- console.log(Clipboard.getText());
16
- asyncGetText().then(console.log);
8
+ if (await Clipboard.hasImage()) {
9
+ console.log(await Clipboard.getImageBase64());
10
+ } else {
11
+ console.log("No Image");
12
+ }
package/index.d.ts CHANGED
@@ -3,10 +3,21 @@
3
3
 
4
4
  /* auto-generated by NAPI-RS */
5
5
 
6
- export function sum(a: number, b: number): number
7
6
  export function availableFormats(): Array<string>
8
- export function getText(): string
9
- export function getTextAsync(): Promise<string>
10
- export function setText(text: string): void
11
- export function getImageBase64(): string
12
- export function setImageBase64(base64Str: string): void
7
+ export function getText(): Promise<string>
8
+ export function setText(text: string): Promise<void>
9
+ export function hasText(): boolean
10
+ export function getImageBinary(): Promise<Array<number>>
11
+ export function getImageBase64(): Promise<string>
12
+ export function setImageBinary(imageBytes: Array<number>): Promise<void>
13
+ export function setImageBase64(base64Str: string): Promise<void>
14
+ export function hasImage(): boolean
15
+ export function getHtml(): Promise<string>
16
+ export function setHtml(html: string): Promise<void>
17
+ export function hasHtml(): boolean
18
+ export function getRtf(): Promise<string>
19
+ export function setRtf(rtf: string): Promise<void>
20
+ export function hasRtf(): boolean
21
+ export function clear(): Promise<void>
22
+ export function watch(): void
23
+ export function callThreadsafeFunction(callback: (...args: any[]) => any): void
package/index.js CHANGED
@@ -295,12 +295,23 @@ if (!nativeBinding) {
295
295
  throw new Error(`Failed to load native binding`)
296
296
  }
297
297
 
298
- const { sum, availableFormats, getText, getTextAsync, setText, getImageBase64, setImageBase64 } = nativeBinding
298
+ const { availableFormats, getText, setText, hasText, getImageBinary, getImageBase64, setImageBinary, setImageBase64, hasImage, getHtml, setHtml, hasHtml, getRtf, setRtf, hasRtf, clear, watch, callThreadsafeFunction } = nativeBinding
299
299
 
300
- module.exports.sum = sum
301
300
  module.exports.availableFormats = availableFormats
302
301
  module.exports.getText = getText
303
- module.exports.getTextAsync = getTextAsync
304
302
  module.exports.setText = setText
303
+ module.exports.hasText = hasText
304
+ module.exports.getImageBinary = getImageBinary
305
305
  module.exports.getImageBase64 = getImageBase64
306
+ module.exports.setImageBinary = setImageBinary
306
307
  module.exports.setImageBase64 = setImageBase64
308
+ module.exports.hasImage = hasImage
309
+ module.exports.getHtml = getHtml
310
+ module.exports.setHtml = setHtml
311
+ module.exports.hasHtml = hasHtml
312
+ module.exports.getRtf = getRtf
313
+ module.exports.setRtf = setRtf
314
+ module.exports.hasRtf = hasRtf
315
+ module.exports.clear = clear
316
+ module.exports.watch = watch
317
+ module.exports.callThreadsafeFunction = callThreadsafeFunction
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crosscopy/clipboard",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "napi": {
@@ -40,13 +40,13 @@
40
40
  "version": "napi version"
41
41
  },
42
42
  "optionalDependencies": {
43
- "@crosscopy/clipboard-win32-x64-msvc": "0.2.3",
44
- "@crosscopy/clipboard-darwin-x64": "0.2.3",
45
- "@crosscopy/clipboard-linux-x64-gnu": "0.2.3",
46
- "@crosscopy/clipboard-darwin-arm64": "0.2.3",
47
- "@crosscopy/clipboard-linux-arm64-gnu": "0.2.3",
48
- "@crosscopy/clipboard-win32-arm64-msvc": "0.2.3",
49
- "@crosscopy/clipboard-darwin-universal": "0.2.3",
50
- "@crosscopy/clipboard-linux-riscv64-gnu": "0.2.3"
43
+ "@crosscopy/clipboard-win32-x64-msvc": "0.2.5",
44
+ "@crosscopy/clipboard-darwin-x64": "0.2.5",
45
+ "@crosscopy/clipboard-linux-x64-gnu": "0.2.5",
46
+ "@crosscopy/clipboard-darwin-arm64": "0.2.5",
47
+ "@crosscopy/clipboard-linux-arm64-gnu": "0.2.5",
48
+ "@crosscopy/clipboard-win32-arm64-msvc": "0.2.5",
49
+ "@crosscopy/clipboard-darwin-universal": "0.2.5",
50
+ "@crosscopy/clipboard-linux-riscv64-gnu": "0.2.5"
51
51
  }
52
52
  }
package/src/lib.rs CHANGED
@@ -1,15 +1,19 @@
1
1
  #![deny(clippy::all)]
2
2
  use base64::{engine::general_purpose, Engine as _};
3
- use clipboard_rs::{common::RustImage, Clipboard, ClipboardContext, ContentFormat, RustImageData};
3
+ use clipboard_rs::{
4
+ common::RustImage, Clipboard, ClipboardContext, ClipboardHandler, ClipboardWatcher,
5
+ ClipboardWatcherContext, ContentFormat, RustImageData,
6
+ };
7
+ use napi::{
8
+ bindgen_prelude::*,
9
+ threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode},
10
+ CallContext, JsFunction, JsString,
11
+ };
12
+ use std::{thread, time::Duration};
4
13
 
5
14
  #[macro_use]
6
15
  extern crate napi_derive;
7
16
 
8
- #[napi]
9
- pub fn sum(a: i32, b: i32) -> i32 {
10
- a + b
11
- }
12
-
13
17
  #[napi]
14
18
  pub fn available_formats() -> Vec<String> {
15
19
  let ctx = ClipboardContext::new().unwrap();
@@ -18,36 +22,171 @@ pub fn available_formats() -> Vec<String> {
18
22
  }
19
23
 
20
24
  #[napi]
21
- pub fn get_text() -> String {
25
+ pub async fn get_text() -> String {
22
26
  let ctx = ClipboardContext::new().unwrap();
23
27
  ctx.get_text().unwrap()
24
28
  }
25
29
 
26
30
  #[napi]
27
- async fn get_text_async() -> String {
31
+ pub async fn set_text(text: String) {
28
32
  let ctx = ClipboardContext::new().unwrap();
29
- ctx.get_text().unwrap()
33
+ ctx.set_text(text).unwrap()
30
34
  }
31
35
 
32
36
  #[napi]
33
- pub fn set_text(text: String) {
37
+ pub fn has_text() -> bool {
34
38
  let ctx = ClipboardContext::new().unwrap();
35
- ctx.set_text(text).unwrap()
39
+ ctx.has(ContentFormat::Text)
36
40
  }
37
41
 
38
42
  #[napi]
39
- pub fn get_image_base64() -> String {
43
+ pub async fn get_image_binary() -> Vec<u8> {
40
44
  let ctx = ClipboardContext::new().unwrap();
41
45
  let image = ctx.get_image().unwrap();
42
46
  let image_bytes = image.to_png().unwrap().get_bytes().to_vec();
47
+ image_bytes
48
+ }
49
+
50
+ #[napi]
51
+ pub async fn get_image_base64() -> String {
52
+ let image_bytes = get_image_binary().await;
43
53
  let base64_str = general_purpose::STANDARD_NO_PAD.encode(&image_bytes);
44
54
  base64_str
45
55
  }
46
56
 
47
57
  #[napi]
48
- pub fn set_image_base64(base64_str: String) {
58
+ pub async fn set_image_binary(image_bytes: Vec<u8>) {
49
59
  let ctx = ClipboardContext::new().unwrap();
50
- let decoded: Vec<u8> = general_purpose::STANDARD_NO_PAD.decode(base64_str).unwrap();
51
- let img = RustImageData::from_bytes(&decoded).unwrap();
60
+ let img = RustImageData::from_bytes(&image_bytes).unwrap();
52
61
  ctx.set_image(img).unwrap()
53
62
  }
63
+
64
+ #[napi]
65
+ pub async fn set_image_base64(base64_str: String) {
66
+ let decoded: Vec<u8> = general_purpose::STANDARD_NO_PAD.decode(base64_str).unwrap();
67
+ set_image_binary(decoded).await;
68
+ }
69
+
70
+ #[napi]
71
+ pub fn has_image() -> bool {
72
+ let ctx = ClipboardContext::new().unwrap();
73
+ ctx.has(ContentFormat::Image)
74
+ }
75
+
76
+ #[napi]
77
+ pub async fn get_html() -> String {
78
+ let ctx = ClipboardContext::new().unwrap();
79
+ ctx.get_html().unwrap()
80
+ }
81
+
82
+ #[napi]
83
+ pub async fn set_html(html: String) {
84
+ let ctx = ClipboardContext::new().unwrap();
85
+ ctx.set_html(html).unwrap()
86
+ }
87
+
88
+ #[napi]
89
+ fn has_html() -> bool {
90
+ let ctx = ClipboardContext::new().unwrap();
91
+ ctx.has(ContentFormat::Html)
92
+ }
93
+
94
+ #[napi]
95
+ pub async fn get_rtf() -> String {
96
+ let ctx = ClipboardContext::new().unwrap();
97
+ ctx.get_rich_text().unwrap()
98
+ }
99
+
100
+ #[napi]
101
+ pub async fn set_rtf(rtf: String) {
102
+ let ctx = ClipboardContext::new().unwrap();
103
+ ctx.set_rich_text(rtf).unwrap()
104
+ }
105
+
106
+ #[napi]
107
+ pub fn has_rtf() -> bool {
108
+ let ctx = ClipboardContext::new().unwrap();
109
+ ctx.has(ContentFormat::Rtf)
110
+ }
111
+
112
+ #[napi]
113
+ pub async fn clear() {
114
+ let ctx = ClipboardContext::new().unwrap();
115
+ ctx.clear().unwrap()
116
+ }
117
+
118
+ struct Manager {
119
+ ctx: ClipboardContext,
120
+ }
121
+
122
+ impl Manager {
123
+ pub fn new() -> Self {
124
+ let ctx = ClipboardContext::new().unwrap();
125
+ Manager { ctx }
126
+ }
127
+ }
128
+
129
+ impl ClipboardHandler for Manager {
130
+ fn on_clipboard_change(&mut self) {
131
+ println!(
132
+ "on_clipboard_change, txt = {}",
133
+ self.ctx.get_text().unwrap()
134
+ );
135
+ }
136
+ }
137
+
138
+ #[napi]
139
+ pub fn watch() {
140
+ let manager = Manager::new();
141
+
142
+ let mut watcher = ClipboardWatcherContext::new().unwrap();
143
+
144
+ let watcher_shutdown = watcher.add_handler(manager).get_shutdown_channel();
145
+
146
+ thread::spawn(move || {
147
+ thread::sleep(Duration::from_secs(5));
148
+ println!("stop watch!");
149
+ watcher_shutdown.stop();
150
+ });
151
+
152
+ println!("start watch!");
153
+ watcher.start_watch();
154
+ }
155
+
156
+
157
+ #[napi]
158
+ pub fn call_threadsafe_function(callback: JsFunction) -> Result<()> {
159
+ let tsfn: ThreadsafeFunction<u32, ErrorStrategy::CalleeHandled> = callback
160
+ .create_threadsafe_function(0, |ctx| {
161
+ ctx.env.create_uint32(ctx.value + 1).map(|v| vec![v])
162
+ })?;
163
+ for n in 0..10 {
164
+ let tsfn = tsfn.clone();
165
+ thread::spawn(move || {
166
+ tsfn.call(Ok(n), ThreadsafeFunctionCallMode::Blocking);
167
+ });
168
+ }
169
+ Ok(())
170
+ }
171
+
172
+ // #[js_function(1)]
173
+ // fn hello(ctx: CallContext) -> Result<JsString, String> {
174
+ // let argument_one = ctx
175
+ // .get::<JsString>(0)
176
+ // .map_err(|err| err.to_string())?
177
+ // .into_utf8()
178
+ // .map_err(|err| err.to_string())?;
179
+ // ctx
180
+ // .env
181
+ // .create_string_from_std(format!("{} world!", argument_one.as_str()?))
182
+ // }
183
+
184
+ #[cfg(test)]
185
+ mod tests {
186
+ use super::*;
187
+
188
+ #[test]
189
+ fn it_works() {
190
+ watch();
191
+ }
192
+ }