// image drag and paste upload import { CoreEditor } from "@halo-dev/richtext-editor"; import type { Attachment } from "@halo-dev/api-client"; import Image from "../extensions/image"; import type { AxiosRequestConfig } from "axios"; export interface FileProps { file: File; editor: CoreEditor; } /** * Handles file events, determining if the file is an image and triggering the appropriate upload process. * * @param {FileProps} { file, editor } - File and editor instances * @returns {boolean} - True if a file is handled, otherwise false */ export const handleFileEvent = ({ file, editor }: FileProps) => { if (!file) { return false; } if (file.type.startsWith("image/")) { uploadImage({ file, editor }); return true; } return true; }; /** * Uploads an image file and inserts it into the editor. * * @param {FileProps} { file, editor } - File to be uploaded and the editor instance */ export const uploadImage = ({ file, editor }: FileProps) => { const { view } = editor; const node = view.props.state.schema.nodes[Image.name].create({ file: file, }); editor.view.dispatch(editor.view.state.tr.replaceSelectionWith(node)); }; export interface UploadFetchResponse { controller: AbortController; onUploadProgress: (progress: number) => void; onFinish: (attachment?: Attachment) => void; onError: (error: Error) => void; } /** * Uploads a file with progress monitoring, cancellation support, and callbacks for completion and errors. * * @param {File} file - File to be uploaded * @param {Function} upload - Function to handle the file upload, should return a Promise * @returns {Promise} - Returns an object with control and callback methods */ export const uploadFile = async ( file: File, upload: (file: File, options?: AxiosRequestConfig) => Promise, uploadResponse: UploadFetchResponse ) => { const { signal } = uploadResponse.controller; upload(file, { signal, onUploadProgress(progressEvent) { const progress = Math.round( (progressEvent.loaded * 100) / (progressEvent.total || 0) ); uploadResponse.onUploadProgress(progress); }, }) .then((attachment) => { uploadResponse.onFinish(attachment); }) .catch((error) => { uploadResponse.onError(error); }); }; /** * Converts a file to a Base64 string. * * @param {File} file - File to be converted * @returns {Promise} - A promise that resolves with the Base64 string */ export function fileToBase64(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = function () { resolve(reader.result as string); }; reader.onerror = function (error) { reject(error); }; reader.readAsDataURL(file); }); }