jg-clipboard 0.1.1 → 0.2.0
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/API.md +5 -5
- package/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/RECIPES.md +1 -1
- package/dist/read/read.d.ts +6 -4
- package/dist/read/read.js +15 -6
- package/dist/read/read.js.map +1 -1
- package/package.json +1 -1
package/API.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# <a id="api-reference"></a>jg-clipboard API reference
|
|
2
2
|
|
|
3
|
-
Every export of `jg-clipboard@0.
|
|
3
|
+
Every export of `jg-clipboard@0.2.0`, 10 in all, with its signature, its errors, and an example. It's generated from the package's TSDoc.
|
|
4
4
|
|
|
5
5
|
- Functions: [`copyHtml`](#api-copyHtml), [`copyImage`](#api-copyImage), [`copyText`](#api-copyText), [`getClipboardSupport`](#api-getClipboardSupport), [`readClipboard`](#api-readClipboard), [`readText`](#api-readText)
|
|
6
6
|
- Constants: [`ERRORS`](#api-ERRORS)
|
|
@@ -153,13 +153,13 @@ if (support.copyImage) {
|
|
|
153
153
|
|
|
154
154
|
*Function*
|
|
155
155
|
|
|
156
|
-
Reads the clipboard's text, HTML, and image with one `read()` call, so the person pasting sees one prompt at most. Call it from a click or key press handler, which Safari requires.
|
|
156
|
+
Reads the clipboard's text, HTML, and image with one `read()` call, so the person pasting sees one prompt at most. Call it from a click or key press handler, which Safari requires. An image the browser can't read never hides the text or HTML copied with it, such as the picture of spreadsheet cells that comes with their text: the image is then null.
|
|
157
157
|
|
|
158
158
|
```ts
|
|
159
159
|
readClipboard(): Promise<IClipboardContent>
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
**Returns** `Promise<IClipboardContent>`: A promise that resolves to each kind of content, with null for the kinds the clipboard doesn't hold. The image is PNG.
|
|
162
|
+
**Returns** `Promise<IClipboardContent>`: A promise that resolves to each kind of content, with null for the kinds the clipboard doesn't hold or the image it can't read. The image is PNG.
|
|
163
163
|
|
|
164
164
|
**Throws**
|
|
165
165
|
|
|
@@ -167,8 +167,8 @@ readClipboard(): Promise<IClipboardContent>
|
|
|
167
167
|
- `CLIPBOARD_NOT_FOCUSED`: The page must have focus to use the clipboard.
|
|
168
168
|
- `CLIPBOARD_NO_USER_GESTURE`: The browser only allows this right after a click or a key press.
|
|
169
169
|
- `CLIPBOARD_PERMISSION_DENIED`: The permission to use the clipboard was denied.
|
|
170
|
-
- `CLIPBOARD_INVALID_IMAGE`: The
|
|
171
|
-
- `CLIPBOARD_READ_FAILED`: The clipboard couldn't be read.
|
|
170
|
+
- `CLIPBOARD_INVALID_IMAGE`: The clipboard holds only an image, which couldn't be decoded as PNG.
|
|
171
|
+
- `CLIPBOARD_READ_FAILED`: The clipboard couldn't be read, or holds only an image it couldn't read.
|
|
172
172
|
|
|
173
173
|
**Example**
|
|
174
174
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- `readClipboard` returns the text and HTML when the clipboard's image can't be read, with `image: null`, instead of failing as a whole. It still throws `CLIPBOARD_INVALID_IMAGE`, or `CLIPBOARD_READ_FAILED`, when the image is all the clipboard holds.
|
|
8
|
+
|
|
3
9
|
## 0.1.1
|
|
4
10
|
|
|
5
11
|
### Added
|
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ await copyHtml('<strong>Order #42</strong> shipped', { text: 'Order #42 shipped'
|
|
|
45
45
|
await copyImage(fetch('/chart.jpg').then((response) => response.blob()));
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Read from a paste button. `readClipboard` reads the text, HTML, and image with one call, so the person pasting sees one prompt at most:
|
|
48
|
+
Read from a paste button. `readClipboard` reads the text, HTML, and image with one call, so the person pasting sees one prompt at most. An image the browser can't read comes back as `null` when text or HTML was copied with it, so the text still pastes:
|
|
49
49
|
|
|
50
50
|
```ts
|
|
51
51
|
import { readClipboard, readText } from 'jg-clipboard';
|
|
@@ -75,7 +75,7 @@ Every failure is an `Exception` with one of these codes, and the browser's error
|
|
|
75
75
|
| `CLIPBOARD_NOT_FOCUSED` | The browser refused because the page doesn't have focus |
|
|
76
76
|
| `CLIPBOARD_NO_USER_GESTURE` | The browser refused because the call didn't follow a click or a key press |
|
|
77
77
|
| `CLIPBOARD_PERMISSION_DENIED` | The browser refused for any other reason, such as a denied or dismissed permission; `data.permission` holds the Permissions API's state, or `null` |
|
|
78
|
-
| `CLIPBOARD_INVALID_IMAGE` | The image can't be decoded,
|
|
78
|
+
| `CLIPBOARD_INVALID_IMAGE` | The image can't be decoded as PNG: an image to copy, or one `readClipboard` read without text or HTML beside it |
|
|
79
79
|
| `CLIPBOARD_WRITE_FAILED` | A copy failed otherwise, such as content whose promise rejected |
|
|
80
80
|
| `CLIPBOARD_READ_FAILED` | A read failed otherwise |
|
|
81
81
|
|
package/RECIPES.md
CHANGED
|
@@ -104,4 +104,4 @@ pasteButton.addEventListener('click', async () => {
|
|
|
104
104
|
});
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
Safari and Firefox show a paste prompt on every read, and Chromium asks for the clipboard-read permission once, so read only when the person clicks. Which content wins when the clipboard holds both depends on the app: copied spreadsheet cells can come with a picture of the cells, so a field for tables would check `text` first. `CLIPBOARD_INVALID_IMAGE` means the clipboard held an image the browser can't decode,
|
|
107
|
+
Safari and Firefox show a paste prompt on every read, and Chromium asks for the clipboard-read permission once, so read only when the person clicks. Which content wins when the clipboard holds both depends on the app: copied spreadsheet cells can come with a picture of the cells, so a field for tables would check `text` first. `CLIPBOARD_INVALID_IMAGE` means the clipboard held only an image the browser can't decode. When text or HTML came with it, `readClipboard` returns them with `image: null` instead, so the paste falls through to the text.
|
package/dist/read/read.d.ts
CHANGED
|
@@ -20,9 +20,11 @@ import { type IClipboardContent } from '../shared/index.js';
|
|
|
20
20
|
export declare const readText: () => Promise<string>;
|
|
21
21
|
/**
|
|
22
22
|
* Reads the clipboard's text, HTML, and image with one `read()` call, so the person pasting sees
|
|
23
|
-
* one prompt at most. Call it from a click or key press handler, which Safari requires.
|
|
23
|
+
* one prompt at most. Call it from a click or key press handler, which Safari requires. An image
|
|
24
|
+
* the browser can't read never hides the text or HTML copied with it, such as the picture of
|
|
25
|
+
* spreadsheet cells that comes with their text: the image is then null.
|
|
24
26
|
* @returns A promise that resolves to each kind of content, with null for the kinds the clipboard
|
|
25
|
-
* doesn't hold. The image is PNG.
|
|
27
|
+
* doesn't hold or the image it can't read. The image is PNG.
|
|
26
28
|
* @example
|
|
27
29
|
* import { readClipboard } from 'jg-clipboard';
|
|
28
30
|
*
|
|
@@ -37,7 +39,7 @@ export declare const readText: () => Promise<string>;
|
|
|
37
39
|
* - CLIPBOARD_NOT_FOCUSED: The page must have focus to use the clipboard.
|
|
38
40
|
* - CLIPBOARD_NO_USER_GESTURE: The browser only allows this right after a click or a key press.
|
|
39
41
|
* - CLIPBOARD_PERMISSION_DENIED: The permission to use the clipboard was denied.
|
|
40
|
-
* - CLIPBOARD_INVALID_IMAGE: The
|
|
41
|
-
* - CLIPBOARD_READ_FAILED: The clipboard couldn't be read.
|
|
42
|
+
* - CLIPBOARD_INVALID_IMAGE: The clipboard holds only an image, which couldn't be decoded as PNG.
|
|
43
|
+
* - CLIPBOARD_READ_FAILED: The clipboard couldn't be read, or holds only an image it couldn't read.
|
|
42
44
|
*/
|
|
43
45
|
export declare const readClipboard: () => Promise<IClipboardContent>;
|
package/dist/read/read.js
CHANGED
|
@@ -55,9 +55,11 @@ const readImage = async (items) => {
|
|
|
55
55
|
};
|
|
56
56
|
/**
|
|
57
57
|
* Reads the clipboard's text, HTML, and image with one `read()` call, so the person pasting sees
|
|
58
|
-
* one prompt at most. Call it from a click or key press handler, which Safari requires.
|
|
58
|
+
* one prompt at most. Call it from a click or key press handler, which Safari requires. An image
|
|
59
|
+
* the browser can't read never hides the text or HTML copied with it, such as the picture of
|
|
60
|
+
* spreadsheet cells that comes with their text: the image is then null.
|
|
59
61
|
* @returns A promise that resolves to each kind of content, with null for the kinds the clipboard
|
|
60
|
-
* doesn't hold. The image is PNG.
|
|
62
|
+
* doesn't hold or the image it can't read. The image is PNG.
|
|
61
63
|
* @example
|
|
62
64
|
* import { readClipboard } from 'jg-clipboard';
|
|
63
65
|
*
|
|
@@ -72,8 +74,8 @@ const readImage = async (items) => {
|
|
|
72
74
|
* - CLIPBOARD_NOT_FOCUSED: The page must have focus to use the clipboard.
|
|
73
75
|
* - CLIPBOARD_NO_USER_GESTURE: The browser only allows this right after a click or a key press.
|
|
74
76
|
* - CLIPBOARD_PERMISSION_DENIED: The permission to use the clipboard was denied.
|
|
75
|
-
* - CLIPBOARD_INVALID_IMAGE: The
|
|
76
|
-
* - CLIPBOARD_READ_FAILED: The clipboard couldn't be read.
|
|
77
|
+
* - CLIPBOARD_INVALID_IMAGE: The clipboard holds only an image, which couldn't be decoded as PNG.
|
|
78
|
+
* - CLIPBOARD_READ_FAILED: The clipboard couldn't be read, or holds only an image it couldn't read.
|
|
77
79
|
*/
|
|
78
80
|
export const readClipboard = async () => {
|
|
79
81
|
const clipboard = getSecureClipboard();
|
|
@@ -92,9 +94,16 @@ export const readClipboard = async () => {
|
|
|
92
94
|
const [text, html, image] = await Promise.all([
|
|
93
95
|
readType(items, 'text/plain'),
|
|
94
96
|
readType(items, 'text/html'),
|
|
95
|
-
|
|
97
|
+
// a failed image is kept as its error, so the text copied with it can still be pasted
|
|
98
|
+
readImage(items).then((png) => ({ png }), (failure) => ({ failure })),
|
|
96
99
|
]);
|
|
97
|
-
|
|
100
|
+
if (!('failure' in image)) {
|
|
101
|
+
return { text, html, image: image.png };
|
|
102
|
+
}
|
|
103
|
+
if (!text && !html) {
|
|
104
|
+
throw image.failure;
|
|
105
|
+
}
|
|
106
|
+
return { text, html, image: null };
|
|
98
107
|
}
|
|
99
108
|
catch (error) {
|
|
100
109
|
throw isException(error)
|
package/dist/read/read.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/read/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,GAEZ,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAqB,EAAE;IAClD,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;IACvC,MAAM,IAAI,GAAG,SAAS,EAAE,QAAQ,CAAC;IACjC,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;AACH,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAqB,EAAE,IAAY,EAA0B,EAAE;IACrF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACvE,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,SAAS,GAAG,KAAK,EAAE,KAAqB,EAAwB,EAAE;IACtE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,KAAK,GACT,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,WAAW,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AAClF,CAAC,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/read/read.ts"],"names":[],"mappings":"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","sourcesContent":["import { Exception, isException } from 'jg-exception';\n\nimport { toPng } from '../copy/image.js';\nimport {\n ERRORS,\n getSecureClipboard,\n toClipboardException,\n unsupported,\n type IClipboardContent,\n} from '../shared/index.js';\n\n/**\n * Reads the text on the clipboard. Browsers ask before a page reads it: Safari and Firefox show a\n * paste prompt, and Chromium asks for the clipboard-read permission once. Call it from a click or\n * key press handler, which Safari requires.\n * @returns A promise that resolves to the text, or `''` when the clipboard holds none.\n * @example\n * import { readText } from 'jg-clipboard';\n *\n * pasteButton.addEventListener('click', async () => {\n * input.value = await readText();\n * });\n * @throws\n * - CLIPBOARD_UNSUPPORTED: The clipboard can't read text here.\n * - CLIPBOARD_NOT_FOCUSED: The page must have focus to use the clipboard.\n * - CLIPBOARD_NO_USER_GESTURE: The browser only allows this right after a click or a key press.\n * - CLIPBOARD_PERMISSION_DENIED: The permission to use the clipboard was denied.\n * - CLIPBOARD_READ_FAILED: The clipboard couldn't be read.\n */\nexport const readText = async (): Promise<string> => {\n const clipboard = getSecureClipboard();\n const read = clipboard?.readText;\n if (typeof read !== 'function') {\n throw unsupported('read text');\n }\n try {\n return await read.call(clipboard);\n } catch (error) {\n throw await toClipboardException(error, 'read');\n }\n};\n\n/**\n * Reads one type from the first item that has it.\n * @param items The clipboard's items.\n * @param type The MIME type.\n * @returns A promise that resolves to the item's text, or null when no item has the type.\n */\nconst readType = async (items: ClipboardItems, type: string): Promise<string | null> => {\n const item = items.find(({ types }) => types.includes(type));\n return item === undefined ? null : (await item.getType(type)).text();\n};\n\n/**\n * Reads the first image, preferring PNG, as PNG.\n * @param items The clipboard's items.\n * @returns A promise that resolves to the PNG, or null when no item holds an image.\n */\nconst readImage = async (items: ClipboardItems): Promise<Blob | null> => {\n const types = items.flatMap((item) => item.types.map((type) => ({ item, type })));\n const image =\n types.find(({ type }) => type === 'image/png') ??\n types.find(({ type }) => type.startsWith('image/'));\n return image === undefined ? null : toPng(await image.item.getType(image.type));\n};\n\n/**\n * Reads the clipboard's text, HTML, and image with one `read()` call, so the person pasting sees\n * one prompt at most. Call it from a click or key press handler, which Safari requires. An image\n * the browser can't read never hides the text or HTML copied with it, such as the picture of\n * spreadsheet cells that comes with their text: the image is then null.\n * @returns A promise that resolves to each kind of content, with null for the kinds the clipboard\n * doesn't hold or the image it can't read. The image is PNG.\n * @example\n * import { readClipboard } from 'jg-clipboard';\n *\n * pasteButton.addEventListener('click', async () => {\n * const { html, text, image } = await readClipboard();\n * if (image) {\n * preview.src = URL.createObjectURL(image);\n * }\n * });\n * @throws\n * - CLIPBOARD_UNSUPPORTED: The clipboard can't read here.\n * - CLIPBOARD_NOT_FOCUSED: The page must have focus to use the clipboard.\n * - CLIPBOARD_NO_USER_GESTURE: The browser only allows this right after a click or a key press.\n * - CLIPBOARD_PERMISSION_DENIED: The permission to use the clipboard was denied.\n * - CLIPBOARD_INVALID_IMAGE: The clipboard holds only an image, which couldn't be decoded as PNG.\n * - CLIPBOARD_READ_FAILED: The clipboard couldn't be read, or holds only an image it couldn't read.\n */\nexport const readClipboard = async (): Promise<IClipboardContent> => {\n const clipboard = getSecureClipboard();\n const read = clipboard?.read;\n if (typeof read !== 'function') {\n throw unsupported('read');\n }\n let items: ClipboardItems;\n try {\n items = await read.call(clipboard);\n } catch (error) {\n throw await toClipboardException(error, 'read');\n }\n try {\n const [text, html, image] = await Promise.all([\n readType(items, 'text/plain'),\n readType(items, 'text/html'),\n // a failed image is kept as its error, so the text copied with it can still be pasted\n readImage(items).then(\n (png) => ({ png }),\n (failure: unknown) => ({ failure }),\n ),\n ]);\n if (!('failure' in image)) {\n return { text, html, image: image.png };\n }\n if (!text && !html) {\n throw image.failure;\n }\n return { text, html, image: null };\n } catch (error) {\n throw isException(error)\n ? error\n : new Exception(\"The clipboard's content couldn't be read.\", {\n code: ERRORS.CLIPBOARD_READ_FAILED,\n cause: error,\n });\n }\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jg-clipboard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Copy and read text, HTML, and images on the browser clipboard, with support detection and coded errors that say why the browser refused.",
|
|
5
5
|
"author": "Jesus Graterol",
|
|
6
6
|
"license": "MIT",
|