expo-paste-input 0.1.1 → 0.1.3
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/README.md +114 -78
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -1,123 +1,159 @@
|
|
|
1
|
-
#
|
|
1
|
+
# expo-paste-input
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`expo-paste-input` is a lightweight wrapper around React Native `TextInput` that lets users paste images and GIFs directly from the system clipboard on **iOS and Android**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It works at the native level to intercept paste events before React Native handles them, giving you access to pasted media as local file URIs while keeping full control over your own `TextInput` component.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
See the original demo on [Twitter](https://x.com/iamarunabh/status/1997738168247062774)
|
|
8
|
+
|
|
9
|
+
| iOS | Android |
|
|
10
|
+
| --- | --- |
|
|
9
11
|
| <video src="https://github.com/user-attachments/assets/b54b15ac-5b98-4dc7-84d7-2e7d48e53e24" /> | <video src="https://github.com/user-attachments/assets/4d709a2c-2dca-431d-8972-05f01b7e5276" /> |
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
---
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## Features
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
- Paste **text, images, and multiple GIFs**
|
|
18
|
+
- Works on **iOS and Android**
|
|
19
|
+
- True wrapper around `TextInput` (bring your own input)
|
|
20
|
+
- No custom UI, no opinionated styles
|
|
21
|
+
- Returns local file URIs for pasted media
|
|
22
|
+
- Safe to import on Web (no crash, no-op)
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
- Handles pasted text and images consistently across iOS and Android
|
|
19
|
-
- Supports pasting multiple images, including GIFs
|
|
20
|
-
- Returns file URIs for pasted images that you can use directly
|
|
24
|
+
---
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
## Installation
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
type PasteEventPayload =
|
|
26
|
-
| { type: "text"; value: string }
|
|
27
|
-
| { type: "images"; uris: string[] }
|
|
28
|
-
| { type: "unsupported" };
|
|
29
|
-
```
|
|
28
|
+
### Quick install
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
```bash
|
|
31
|
+
npx expo install expo-paste-input
|
|
32
|
+
````
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
or
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
```bash
|
|
37
|
+
yarn add expo-paste-input
|
|
38
|
+
```
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
### Rebuild the app (required)
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
- For **text**: The original paste proceeds normally, and the pasted text is forwarded to JavaScript.
|
|
42
|
+
This library uses native code, so you must rebuild.
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
```bash
|
|
45
|
+
npx expo run:ios
|
|
46
|
+
npx expo run:android
|
|
47
|
+
```
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
(Expo Go will not work)
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
---
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
- For **text**: The original paste proceeds normally, and the pasted text is forwarded to JavaScript.
|
|
53
|
+
## Usage
|
|
50
54
|
|
|
51
|
-
|
|
55
|
+
Wrap your `TextInput` with `TextInputWrapper`:
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
```tsx
|
|
58
|
+
import { TextInputWrapper } from "expo-paste-input";
|
|
59
|
+
import { TextInput } from "react-native";
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
export default function MyInput() {
|
|
62
|
+
return (
|
|
63
|
+
<TextInputWrapper
|
|
64
|
+
onPaste={(payload) => {
|
|
65
|
+
console.log(payload);
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<TextInput placeholder="Paste here..." />
|
|
69
|
+
</TextInputWrapper>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
56
73
|
|
|
57
|
-
|
|
74
|
+
---
|
|
58
75
|
|
|
59
|
-
|
|
76
|
+
## Props
|
|
60
77
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
78
|
+
| Prop | Type | Description |
|
|
79
|
+
| -------- | -------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
80
|
+
| children | `React.ReactElement` | The `TextInput` (or any custom input) you want to wrap. |
|
|
81
|
+
| onPaste | `(payload: PasteEventPayload) => void` | Callback fired when a paste event is detected. Receives pasted text or image URIs. |
|
|
82
|
+
|
|
83
|
+
---
|
|
64
84
|
|
|
65
|
-
|
|
66
|
-
|
|
85
|
+
## Types
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
type PasteEventPayload =
|
|
89
|
+
| { type: "text"; value: string }
|
|
90
|
+
| { type: "images"; uris: string[] }
|
|
91
|
+
| { type: "unsupported" };
|
|
67
92
|
```
|
|
68
93
|
|
|
69
|
-
|
|
94
|
+
* `text` → pasted text
|
|
95
|
+
* `images` → local file URIs (`file://...`)
|
|
96
|
+
* `unsupported` → anything else
|
|
70
97
|
|
|
71
|
-
|
|
98
|
+
---
|
|
72
99
|
|
|
73
|
-
|
|
74
|
-
import {
|
|
75
|
-
TextInputWrapper,
|
|
76
|
-
PasteEventPayload,
|
|
77
|
-
} from "@/modules/text-input-wrapper";
|
|
78
|
-
import { TextInput } from "react-native";
|
|
100
|
+
## Why a wrapper?
|
|
79
101
|
|
|
80
|
-
|
|
81
|
-
const handlePaste = (payload: PasteEventPayload) => {
|
|
82
|
-
if (payload.type === "images") {
|
|
83
|
-
// payload.uris contains file:// URIs for each pasted image
|
|
84
|
-
console.log("Pasted images:", payload.uris);
|
|
85
|
-
} else if (payload.type === "text") {
|
|
86
|
-
// payload.value contains the pasted text
|
|
87
|
-
console.log("Pasted text:", payload.value);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
102
|
+
This library does **not** reimplement `TextInput`.
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
104
|
+
Instead:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<TextInputWrapper>
|
|
108
|
+
<TextInput />
|
|
109
|
+
</TextInputWrapper>
|
|
97
110
|
```
|
|
98
111
|
|
|
112
|
+
This means:
|
|
113
|
+
|
|
114
|
+
* you keep full control of your input
|
|
115
|
+
* works with any custom TextInput
|
|
116
|
+
* no prop mirroring
|
|
117
|
+
* future-proof with RN updates
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Platform behavior
|
|
122
|
+
|
|
123
|
+
### iOS
|
|
124
|
+
|
|
125
|
+
* Intercepts native `paste(_:)`
|
|
126
|
+
* Extracts images from `UIPasteboard`
|
|
127
|
+
* Saves to temp files
|
|
128
|
+
* Preserves GIFs
|
|
129
|
+
|
|
130
|
+
### Android
|
|
131
|
+
|
|
132
|
+
* Uses `OnReceiveContentListener` + `ActionMode`
|
|
133
|
+
* Prevents Android "Can't paste images" toast
|
|
134
|
+
* Saves pasted media to cache
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
99
138
|
## Notes
|
|
100
139
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- Image paste events _prevent_ the default paste (since TextInput can't display images)
|
|
140
|
+
* Image URIs are temporary files, move them if you need persistence.
|
|
141
|
+
* Text paste events fire after the text is inserted.
|
|
142
|
+
* Image paste events prevent default paste (since TextInput can't render images).
|
|
143
|
+
* Web is currently a no-op implementation.
|
|
106
144
|
|
|
107
|
-
|
|
145
|
+
---
|
|
108
146
|
|
|
109
147
|
## Inspiration
|
|
110
148
|
|
|
111
|
-
|
|
149
|
+
Inspired by work from:
|
|
112
150
|
|
|
113
|
-
- **
|
|
114
|
-
- Blog + context: how native paste handling works in v0
|
|
115
|
-
- 𝕏: **[How we built the v0 iOS app](https://x.com/fernandorojo/status/1993098916456452464)**
|
|
116
|
-
- **[v0](https://v0.dev)** — The real-world product discussed in Fernando Rojo’s writing
|
|
151
|
+
- **Fernando Rojo** — [native paste handling in the v0 app](https://x.com/fernandorojo/status/1993098916456452464)
|
|
117
152
|
|
|
118
|
-
|
|
153
|
+
- **v0.dev** — real-world product pushing React Native closer to native UX
|
|
119
154
|
|
|
120
155
|
---
|
|
121
156
|
|
|
122
|
-
|
|
123
|
-
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-paste-input",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A wrapper around React Native TextInput to paste images and GIFs from the clipboard (iOS, Android, Web)",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -18,8 +18,15 @@
|
|
|
18
18
|
"keywords": [
|
|
19
19
|
"react-native",
|
|
20
20
|
"expo",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
21
|
+
"react-native-paste-input",
|
|
22
|
+
"react-native-image-paste-input",
|
|
23
|
+
"clipboard",
|
|
24
|
+
"paste",
|
|
25
|
+
"paste-image",
|
|
26
|
+
"paste-gif",
|
|
27
|
+
"textinput",
|
|
28
|
+
"react-native-clipboard",
|
|
29
|
+
"react-native-textinput"
|
|
23
30
|
],
|
|
24
31
|
"repository": "https://github.com/arunabhverma/expo-paste-input",
|
|
25
32
|
"bugs": {
|