Rich Paste
Rich paste and drag-and-drop support for NativeScript text inputs. Handles images, GIFs, files, and text from the clipboard with one shared TypeScript API across iOS and Android.
The plugin supports:
- Pasting images, GIFs, and static images from the clipboard
- Pasting files (PDF, RTF, HTML) from the clipboard
- Drag-and-drop of images and files into text inputs
- MIME-based accept filtering (
all,image/*,text/plain, etc.) - Drop-in replacements for TextField and TextView
- Automatic temp file management for pasted binary content
Installation
npm install @nstudio/nativescript-rich-pasteUsage
NativeScript Core
Drop-in replacements for TextField and TextView which work identically but with enhanced rich paste features. Just append RichPaste to the end of the element name.
<Page xmlns:rp="@nstudio/nativescript-rich-paste">
<StackLayout class="p-20">
<rp:TextFieldRichPaste accept="all" hint="Paste rich data..." paste="{{ onPaste }}" />
<rp:TextViewRichPaste accept="image/*" hint="Drop images here..." enableDragDrop="true" paste="{{ onPaste }}" drop="{{ onDrop }}" />
</StackLayout>
</Page>import { EventData, Page } from '@nativescript/core';
import { PasteEventData } from '@nstudio/nativescript-rich-paste';
export function navigatingTo(args: EventData) {
const page = args.object as Page;
page.bindingContext = new DemoModel();
}
class DemoModel {
onPaste(args: PasteEventData) {
const payload = args.data;
switch (payload.type) {
case 'text':
console.log('Text:', payload.value);
break;
case 'images':
payload.items.forEach((img) => {
console.log(img.uri, img.mimeType, img.animated);
});
break;
case 'files':
payload.items.forEach((file) => {
console.log(file.name, file.mimeType, file.size);
});
break;
}
}
onDrop(args: PasteEventData) {
console.log('Dropped:', args.data);
}
}Angular
import { registerElement } from '@nativescript/angular';
import { TextFieldRichPaste, TextViewRichPaste } from '@nstudio/nativescript-rich-paste';
registerElement('TextFieldRichPaste', () => TextFieldRichPaste);
registerElement('TextViewRichPaste', () => TextViewRichPaste);<TextFieldRichPaste
accept="all"
hint="Paste rich data..."
(paste)="onPaste($event)"
></TextFieldRichPaste>
<TextViewRichPaste
accept="image/*"
hint="Drop images here..."
enableDragDrop="true"
(paste)="onPaste($event)"
(drop)="onDrop($event)"
></TextViewRichPaste>Other Flavors
import { TextFieldRichPaste, TextViewRichPaste } from '@nstudio/nativescript-rich-paste';
// Vue
registerElement('TextFieldRichPaste', () => TextFieldRichPaste);
registerElement('TextViewRichPaste', () => TextViewRichPaste);
// React
registerElement('textFieldRichPaste', () => TextFieldRichPaste);
registerElement('textViewRichPaste', () => TextViewRichPaste);
// Svelte
registerNativeViewElement('textFieldRichPaste', () => TextFieldRichPaste);
registerNativeViewElement('textViewRichPaste', () => TextViewRichPaste);
// Solid
registerElement('textFieldRichPaste', TextFieldRichPaste);
registerElement('textViewRichPaste', TextViewRichPaste);Paste Payload
The paste and drop events emit a PasteEventData object whose data property is a discriminated union:
Text
interface PasteTextPayload {
type: 'text';
value: string;
}Images
interface PasteImagesPayload {
type: 'images';
items: PasteImageItem[];
}
interface PasteImageItem {
uri: string; // file:// URI to a temp file
mimeType: string; // e.g. 'image/png', 'image/gif'
width?: number;
height?: number;
animated: boolean; // true for GIFs
}Files
interface PasteFilesPayload {
type: 'files';
items: PasteFileItem[];
}
interface PasteFileItem {
uri: string; // file:// URI to a temp file
mimeType: string; // e.g. 'application/pdf'
name?: string;
size?: number;
}Unsupported
Returned when the clipboard contains data that does not match the accept filter.
interface PasteUnsupportedPayload {
type: 'unsupported';
availableTypes: string[];
}Events
paste
Emitted when rich content is pasted from the clipboard.
import { PasteEventData } from '@nstudio/nativescript-rich-paste';
function onPaste(args: PasteEventData) {
const payload = args.data;
console.log('Paste type:', payload.type);
}For text pastes, the default TextField/TextView behavior still applies (the text is inserted into the field) and the paste event is also fired.
drop
Emitted when content is dragged and dropped onto the input. Requires enableDragDrop="true".
import { DropEventData } from '@nstudio/nativescript-rich-paste';
function onDrop(args: DropEventData) {
const payload = args.data;
console.log('Drop type:', payload.type);
}Properties
| Property | Type | Default | Description |
|---|---|---|---|
| accept | string | 'all' | MIME filter for accepted paste content |
| enableDragDrop | boolean | false | Enable drag-and-drop support |
accept filter
The accept property controls which content types are processed. Supported values:
'all'— accept everything (default)'image/*'— accept all image types'image/png'— accept only PNG images'image/gif'— accept only GIF images'text/plain'— accept only plain text'application/pdf'— accept only PDF files- Comma-separated — e.g.
'image/*,application/pdf'
Classes
- TextFieldRichPaste — extends NativeScript TextField
- TextViewRichPaste — extends NativeScript TextView
Both classes expose the same accept, enableDragDrop properties and emit paste and drop events.
Temp File Management
Pasted binary content (images, files) is written to temporary files under the app's temp directory. You can clean up temp files at any time:
import { PasteInputTempFiles } from '@nstudio/nativescript-rich-paste';
// Remove all temp files created by rich paste
PasteInputTempFiles.cleanupAll();Platform Notes
iOS
- Uses custom UITextField/UITextView subclasses that intercept the native
paste:action - Reads from
UIPasteboard.generalPasteboardwith support for images, GIFs, file URLs, and UTI-based document types - Drag-and-drop uses
UIDropInteractionwith a native delegate - GIF animation is preserved by detecting
com.compuserve.gifUTI and writing raw data to temp files - Supports file reference URL resolution including Finder bookmark data
Android
- Uses
OnReceiveContentListeneron API 31+ for unified paste and drag-and-drop handling - Falls back to
onTextContextMenuIteminterception on older API levels - Resolves MIME types via ContentResolver, file extension mapping, and ClipDescription
- Validates GIF files by checking the file header magic bytes
- Images are decoded via
BitmapFactoryand compressed to JPEG temp files
License
Apache License Version 2.0