Image plugin for Plate rich text editor that enables embedding, uploading, and managing images with advanced features like drag-and-drop, resizing, and captions.
—
Functions for programmatically inserting images and utility functions for image URL validation.
Function for programmatically inserting image elements into the Plate editor.
/**
* Inserts an image element at the current cursor position
* Creates a properly structured image element with the provided URL
* @param editor - Plate editor instance
* @param url - Image URL (string) or data (ArrayBuffer) to insert
*/
function insertImage<V extends Value>(
editor: PlateEditor<V>,
url: string | ArrayBuffer
): void;Element Creation:
TImageElement with proper type and structureUsage Examples:
import { insertImage } from "@udecode/plate-image";
import { useEditorRef } from "@udecode/plate-core";
// Insert image from URL
function InsertImageButton({ imageUrl }: { imageUrl: string }) {
const editor = useEditorRef();
const handleInsert = () => {
insertImage(editor, imageUrl);
};
return (
<button onClick={handleInsert}>
Insert Image
</button>
);
}
// Insert multiple images
function InsertImageGallery({ imageUrls }: { imageUrls: string[] }) {
const editor = useEditorRef();
const insertGallery = () => {
imageUrls.forEach((url, index) => {
// Insert with slight delay to ensure proper positioning
setTimeout(() => {
insertImage(editor, url);
}, index * 100);
});
};
return (
<button onClick={insertGallery}>
Insert Gallery ({imageUrls.length} images)
</button>
);
}
// Insert image from file upload
function FileUploadImageInserter() {
const editor = useEditorRef();
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file && file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result) {
insertImage(editor, e.target.result as string);
}
};
reader.readAsDataURL(file);
}
};
return (
<input
type="file"
accept="image/*"
onChange={handleFileUpload}
/>
);
}
// Insert with custom image processing
async function insertProcessedImage(
editor: PlateEditor,
rawImageData: string | ArrayBuffer
) {
try {
// Process or upload image first
const processedUrl = await processImageData(rawImageData);
insertImage(editor, processedUrl);
} catch (error) {
console.error('Failed to process image:', error);
// Fallback to raw data
insertImage(editor, rawImageData);
}
}Utility function to determine if a given URL points to an image file based on file extension.
/**
* Checks if a URL points to an image file
* Validates both URL format and file extension against comprehensive image format list
* @param url - URL string to validate
* @returns Boolean indicating whether URL is a valid image URL
*/
function isImageUrl(url: string): boolean;Validation Process:
isUrl helperSupported Image Formats:
Usage Examples:
import { isImageUrl } from "@udecode/plate-image";
// Basic URL validation
const urls = [
'https://example.com/image.jpg', // true
'https://example.com/image.png', // true
'https://example.com/document.pdf', // false
'not-a-url', // false
'https://example.com/image.webp', // true
];
urls.forEach(url => {
console.log(`${url}: ${isImageUrl(url)}`);
});
// Use in paste handler
function handlePaste(event: ClipboardEvent) {
const text = event.clipboardData?.getData('text/plain');
if (text && isImageUrl(text)) {
console.log('Pasted text is an image URL:', text);
insertImage(editor, text);
event.preventDefault();
}
}
// Filter image URLs from mixed content
function filterImageUrls(urls: string[]): string[] {
return urls.filter(isImageUrl);
}
// Validate before insertion
function safeInsertImage(editor: PlateEditor, url: string) {
if (isImageUrl(url)) {
insertImage(editor, url);
return true;
} else {
console.warn('Invalid image URL:', url);
return false;
}
}
// Custom validation with fallback
function validateAndInsertImage(editor: PlateEditor, url: string) {
if (isImageUrl(url)) {
insertImage(editor, url);
} else {
// Try to detect image by MIME type or other means
fetch(url, { method: 'HEAD' })
.then(response => {
const contentType = response.headers.get('content-type');
if (contentType?.startsWith('image/')) {
insertImage(editor, url);
} else {
console.error('URL does not point to an image');
}
})
.catch(error => {
console.error('Failed to validate URL:', error);
});
}
}import { insertImage, isImageUrl } from "@udecode/plate-image";
import { Transforms } from "slate";
// Insert multiple images with spacing
async function insertImageBatch(
editor: PlateEditor,
urls: string[],
spacing: boolean = true
) {
const validUrls = urls.filter(isImageUrl);
for (let i = 0; i < validUrls.length; i++) {
insertImage(editor, validUrls[i]);
if (spacing && i < validUrls.length - 1) {
// Insert paragraph between images
Transforms.insertNodes(editor, {
type: 'p',
children: [{ text: '' }]
});
}
}
}
// Replace selected content with image
function replaceSelectionWithImage(editor: PlateEditor, url: string) {
if (isImageUrl(url)) {
// Delete current selection
if (editor.selection) {
Transforms.delete(editor);
}
insertImage(editor, url);
}
}// Insert image with upload progress tracking
async function insertImageWithUpload(
editor: PlateEditor,
file: File,
onProgress?: (percent: number) => void
) {
try {
// Create temporary data URL for immediate display
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result) {
insertImage(editor, e.target.result as string);
}
};
reader.readAsDataURL(file);
// Upload file and replace with final URL
const uploadedUrl = await uploadWithProgress(file, onProgress);
// Replace temporary image with uploaded version
// (Implementation would need to track and update the specific image)
} catch (error) {
console.error('Upload failed:', error);
}
}
// Utility for drag-and-drop integration
function handleImageDrop(
editor: PlateEditor,
event: DragEvent,
uploadFunction?: (file: File) => Promise<string>
) {
event.preventDefault();
const files = Array.from(event.dataTransfer?.files || []);
const imageFiles = files.filter(file => file.type.startsWith('image/'));
imageFiles.forEach(async (file) => {
if (uploadFunction) {
try {
const url = await uploadFunction(file);
insertImage(editor, url);
} catch (error) {
// Fallback to data URL
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result) {
insertImage(editor, e.target.result as string);
}
};
reader.readAsDataURL(file);
}
} else {
// Direct data URL insertion
const reader = new FileReader();
reader.onload = (e) => {
if (e.target?.result) {
insertImage(editor, e.target.result as string);
}
};
reader.readAsDataURL(file);
}
});
}// Robust image insertion with validation and error handling
async function safeInsertImage(
editor: PlateEditor,
urlOrData: string | ArrayBuffer,
options?: {
validateUrl?: boolean;
maxSize?: number;
allowedFormats?: string[];
}
) {
try {
// Validate URL if it's a string
if (typeof urlOrData === 'string') {
if (options?.validateUrl && !isImageUrl(urlOrData)) {
throw new Error('Invalid image URL format');
}
// Optional: Check if URL is accessible
if (options?.validateUrl) {
const response = await fetch(urlOrData, { method: 'HEAD' });
if (!response.ok) {
throw new Error(`Image URL not accessible: ${response.status}`);
}
}
}
// Insert the image
insertImage(editor, urlOrData);
return true;
} catch (error) {
console.error('Failed to insert image:', error);
// Optional: Show user-friendly error message
if (typeof urlOrData === 'string') {
console.log('Failed URL:', urlOrData);
}
return false;
}
}Install with Tessl CLI
npx tessl i tessl/npm-udecode--plate-image